Objective c что это
Перейти к содержимому

Objective c что это

  • автор:

 

Зачем учить Objective-C в 2022 году: умелое управление памятью и другие операции на низком уровне

Мобильные разработчики в КРОК решают реальные проблемы заказчиков и конечных пользователей: создают приложения для удалённой проверки остроты зрения, интеграции с умными очками для полиции Дубая или доступа к корпоративной социальной сети. В этой статье команда мобильной разработки рассказала, почему Objective-C до сих пор жив и зачем его учить в 2022 году.

Глубокое понимание процессов

Большая часть внутреннего кода macOS, XCode и ядра iOS написаны на C и С++. Objective-C очень хорошо с ними «стыкуется», потому что формально это не язык программирования, а большой препроцессор к чистому Cи.

Поверх Objective-C строится вся экосистема Apple. Тот же Swift во многом написан поверх него, и чтобы понимать, как система работает изнутри и почему Swift выглядит так, как выглядит, и работает так, как работает, «базу» полезно знать.

Например, Objective-C помогает понять, что не все NSProxy это NSObject и в чём разница между Int, NSInteger и NSNumbe. А также за счёт чего работает Swizzling, что такое Selector, как работает responder chain и так далее. В Swift это сильно инкапсулировано и абстрагировано, а потому не очень хорошо видно.

Кроме того, Objective-C, как и любой Cи-язык, помогает разобраться в том, как работают ссылки, указатели и память в принципе. В нём приходится работать со ссылками напрямую, поэтому достаточно написать 1-2 небольших проекта, чтобы понять тему.

Плюсы на собеседовании

На большинстве собеседований вам будут задавать каверзные вопросы об операциях, которые видны при разработке на Objective-C, но редко встречаются в Swift.

Например, атомарность и атрибуты копирования. Долгое время контроль памяти в Objective-C был ручным, и атомарность — то есть доступность переменных одновременно из разных тредов — достаточно больная тема. Поэтому, проработав N времени на Objective-C, ты начинаешь неплохо в этом разбираться: можешь объяснить, какие проблемы возникают в работе с тредами, когда нужно предусмотреть атомарность или подумать о том, как будет копироваться значение, нужен ли дополнительный акцессор.

Objective-C до сих пор используется в разработке

Во-первых, кажется, у любого проекта, который существует больше 2-3 лет, часть кодовой базы написана на Objective-C. Это может быть хоть скрытый слой, который вынесен в зависимость и не особо стыкуется с общей кодовой базой — но он есть и с ним периодически нужно работать: править баги или добавлять фичи.

Во-вторых, пока некоторые приложения не получается переписать на Swift — это требует времени и денег, которые компания или заказчик не готовы тратить. Поэтому база Objective-C разрастается.

В-третьих, если необходима сложная работа с сетью, памятью, ресурсами устройства, то приходится использовать языки с более низким уровнем абстракции, чем у Swift. Это могут быть Objective-C, Objective-C++ или просто C и С++ — в зависимости от того, насколько низкий уровень нам нужен.

Подобное встречается довольно редко, например в работе с мессенджерами (Telegram), потоковым вещанием (Zoom) или видеосервисами (Кинопоиск). В таких случаях тоже можно абстрагироваться и либо вынести часть логики в отдельную зависимость, либо перенести рендеринг или всю логику пакетирования данных на бэкенд. Но не всегда.

Некоторые вещи сложнее делать на Swift, чем на Objective-C

Иногда решать задачи на Swift долго и неудобно — проще воспользоваться костылями, которые давно есть в Objective-C.

Check Point: троян удалённого доступа впервые попал в десятку популярнейших цифровых угроз

В основном речь идёт про управление памятью: протянуть сообщение в несанкционированную память, вручную поманипулировать управлением памятью или тредами. Разберём пару кейсов.

В Objective-C есть чисто «сишные» штуки: memory allocation, управление указателями и ссылками напрямую и так далее. Поэтому там, где нужно очень аккуратно работать с памятью (например, при работе с видео- и аудиопотоками), c помощью Objective-C можно тонко оптимизировать приложение, улучшить производительность и оценки по памяти. В Swift же придётся полагаться на ARC (хотя и тут есть свои лайфхаки).

Кроме того, ARC не решает многих проблем — например, с длительностью жизни объектов. Допустим, у нас есть голосовое сообщение на 14 минут. Пользователь уже прослушал 12 — и они «съели» всю оперативную память. На Objective-C мы легко можем их почистить — на уровне указателей и байтов — оставив только текущую минуту и две последних. А на Swift это потребует высокого уровня абстракции и большого количества кода (либо использования трюков Objective-C через Swift-интерфейс).

Наконец, зачастую нагруженные, сложные и высоко оптимизированные библиотеки, реализующие распознавание видео или фото, компьютерное зрение или криптографические вычисления, написаны на С++. И интегрироваться с ними через Swift больно, долго и дорого. Как правило, легче создать заголовочный файл в Objective-C, написать пару методов для красивой обёртки и обратиться уже к ним. Такие кейсы очень часто встречаются при интеграции с третьими библиотеками.

Что в итоге?

Да, Objective-C не идеален, но его полезно выучить.

Это по-прежнему востребованный язык программирования. Он помогает лучше понять, как устроен Swift и экосистема Apple в целом, позволяет гранулярно работать с низкоуровневыми задачами. Кроме того, на Objective-C всё ещё написана больша́я часть кодовой базы, которую нужно поддерживать. И наконец, знание языка — это бонус на собеседованиях.

Objective-C: история создания, возможности и особенности

Сегодня речь пойдет об одном из самых легендарных языков программирования – Objective-C. Это довольно сложный язык, с высоким порогом входа, на котором написано огромное количество приложений для macOS, iPad и iPhone.

iPhone тоже работает на Objective-C

iPhone тоже работает на Objective-C

Отличительная особенность этого языка состоит в том, что оно является расширением для другого языка программирования – С. Несмотря на то, что в последнее время Objective-C существенно уступает более прогрессивному, простому и удобному SWIFT, разработка Apple все еще остается актуальной и вызывает интерес.

История появления Objective-C

Все началось в начале 70-х годов прошлого века. На заре программирования использовалась структурная парадигма написания кода. Такая архитектура подразумевала, что все программы строились на трех конструкциях: последовательность, ветвление и цикл (плюс подпрограммы). Подобная методология имела существенный недостаток, который становился все более очевидным по мере усложнения программ – код получался все более запутанным. Возникла необходимость в появлении какой-то технологии, которая бы позволила более рационально использовать код.

Smalltalk-80: The Language and Its Implementation: Amazon.co.uk: Goldberg, Adele, Robson, David: 9780201113716: Books

Книга о Smalltalk-80

Таким решением стал один из первых объектно-ориентированных языков с динамической типизацией – Smalltalk. Забавно, что, хотя он разрабатывался в семидесятых, его более или менее сформировавшаяся версия называлась Smalltalk-80 (наверное, его разработчики из научно-исследовательского центра Xerox PARC давали имя с прицелом на будущее). Уже в то время Smalltalk мог похвастаться возможностями, которые остаются актуальными и по сей день – у него был сборщик мусора, динамическая типизация. Программы, написанные на Smalltalk компилировались в байткод и выполнялись виртуальной машиной, что позволяло запускать код на любом оборудовании.

Взяв за основу главные принципы языка Smalltalk, был создан Objective-C. Создателем Objective-C считается Брэд Кокс, который старался в начале восьмидесятых сделать такой язык программирования, в котором была бы решена проблема повторяемости кода. Objective-C строился на базовых допущениях: класс – самостоятельный полноценный объект, передача сообщений между классами, динамическое типизирование. Самое главное, что отличало этот язык — гибкость. Программист мог писать код на С, а затем просто вставлять его в Objective-C и программа работала. Steve Jobs | Biography, Education, Apple, & Facts | Britannica

В 1985 году Стивом Джобсом, после его увольнения из Apple, была организована компания NeXT, в которую ушли работать несколько разработчиков из Apple. Стив Джобс выбрал для разработки будущих проектов Objective-C, который уже развивался несколько лет и был довольно перспективным проектом, да еще и кросс-совместим с языком С. Objective-C стал базовым языком программирования для операционной системы NeXTEP OS.

Интерфейс NeXTEP OS

В 1988 программисты NeXT разработали для Objective-C компилятор и SDK. А в 1992 году доработкой Objective-C и компилятора занялись также и участники проекта GNU, так GCC получил совместимость с Objective-C. С покупкой NeXT, Apple приобрела и этот SDK (включая компилятор, библиотеки и среду разработки). IDE получило название Xcode, а GUI – Interface Builder. Фреймворк Cocoa (API для macOS) сейчас является наиболее популярной средой разработки программ на Objective-C.

Современная ОС от Apple

В феврале 2008 Apple представил iPhone SDK 2.0, который позволял разрабатывать программы под платформу iOS. Это поспособствовало популяризации языка программирования Objective-C и дало возможность компании Стива Джобса быстро заполнить AppStore огромным числом приложений.

Синтаксис

С Objective-C можно работать практически на любом дистрибутиве GNU/Linux через компилятор gobjc, включенный в набор компиляторов GNU Compiler Collection.

About Objective-C

Objective-C is the primary programming language you use when writing software for OS X and iOS. It’s a superset of the C programming language and provides object-oriented capabilities and a dynamic runtime. Objective-C inherits the syntax, primitive types, and flow control statements of C and adds syntax for defining classes and methods. It also adds language-level support for object graph management and object literals while providing dynamic typing and binding, deferring many responsibilities until runtime.

At a Glance

This document introduces the Objective-C language and offers extensive examples of its use. You’ll learn how to create your own classes describing custom objects and see how to work with some of the framework classes provided by Cocoa and Cocoa Touch. Although the framework classes are separate from the language, their use is tightly wound into coding with Objective-C and many language-level features rely on behavior offered by these classes.

An App Is Built from a Network of Objects

When building apps for OS X or iOS, you’ll spend most of your time working with objects. Those objects are instances of Objective-C classes, some of which are provided for you by Cocoa or Cocoa Touch and some of which you’ll write yourself.

If you’re writing your own class, start by providing a description of the class that details the intended public interface to instances of the class. This interface includes the public properties to encapsulate relevant data, along with a list of methods. Method declarations indicate the messages that an object can receive, and include information about the parameters required whenever the method is called. You’ll also provide a class implementation, which includes the executable code for each method declared in the interface.

Categories Extend Existing Classes

Rather than creating an entirely new class to provide minor additional capabilities over an existing class, it’s possible to define a category to add custom behavior to an existing class. You can use a category to add methods to any class, including classes for which you don’t have the original implementation source code, such as framework classes like NSString .

If you do have the original source code for a class, you can use a class extension to add new properties, or modify the attributes of existing properties. Class extensions are commonly used to hide private behavior for use either within a single source code file, or within the private implementation of a custom framework.

Protocols Define Messaging Contracts

The majority of work in an Objective-C app occurs as a result of objects sending messages to each other. Often, these messages are defined by the methods declared explicitly in a class interface. Sometimes, however, it is useful to be able to define a set of related methods that aren’t tied directly to a specific class.

Objective-C uses protocols to define a group of related methods, such as the methods an object might call on its delegate , which are either optional or required. Any class can indicate that it adopts a protocol, which means that it must also provide implementations for all of the required methods in the protocol.

Relevant Chapters: Working with Protocols

Values and Collections Are Often Represented as Objective-C Objects

It’s common in Objective-C to use Cocoa or Cocoa Touch classes to represent values. The NSString class is used for strings of characters, the NSNumber class for different types of numbers such as integer or floating point, and the NSValue class for other values such as C structures. You can also use any of the primitive types defined by the C language, such as int , float or char .

Collections are usually represented as instances of one of the collection classes, such as NSArray , NSSet , or NSDictionary , which are each used to collect other Objective-C objects.

Relevant Chapters: Values and Collections

Blocks Simplify Common Tasks

Blocks are a language feature introduced to C, Objective-C and C++ to represent a unit of work; they encapsulate a block of code along with captured state, which makes them similar to closures in other programming languages. Blocks are often used to simplify common tasks such as collection enumeration, sorting and testing. They also make it easy to schedule tasks for concurrent or asynchronous execution using technologies like Grand Central Dispatch (GCD).

Relevant Chapters: Working with Blocks

Error Objects Are Used for Runtime Problems

Although Objective-C includes syntax for exception handling, Cocoa and Cocoa Touch use exceptions only for programming errors (such as out of bounds array access), which should be fixed before an app is shipped.

All other errors—including runtime problems such as running out of disk space or not being able to access a web service—are represented by instances of the NSError class. Your app should plan for errors and decide how best to handle them in order to present the best possible user experience when something goes wrong.

Relevant Chapters: Dealing with Errors

Objective-C Code Follows Established Conventions

When writing Objective-C code, you should keep in mind a number of established coding conventions. Method names, for example, start with a lowercase letter and use camel case for multiple words; for example, doSomething or doSomethingElse . It’s not just the capitalization that’s important, though; you should also make sure that your code is as readable as possible, which means that method names should be expressive, but not too verbose.

In addition, there are a few conventions that are required if you wish to take advantage of language or framework features. Property accessor methods, for example, must follow strict naming conventions in order to work with technologies like Key-Value Coding (KVC) or Key-Value Observing (KVO).

Relevant Chapters: Conventions

Prerequisites

If you are new to OS X or iOS development, you should read through Start Developing iOS Apps Today (Retired) or Start Developing Mac Apps Today before reading this document, to get a general overview of the application development process for iOS and OS X. Additionally, you should become familiar with Xcode before trying to follow the exercises at the end of most chapters in this document. Xcode is the IDE used to build apps for iOS and OS X; you’ll use it to write your code, design your app’s user interface, test your application, and debug any problems.

Although it’s preferable to have some familiarity with C or one of the C-based languages such as Java or C#, this document does include inline examples of basic C language features such as flow control statements. If you have knowledge of another higher-level programming language, such as Ruby or Python, you should be able to follow the content.

Reasonable coverage is given to general object-oriented programming principles, particularly as they apply in the context of Objective-C, but it is assumed that you have at least a minimal familiarity with basic object-oriented concepts. If you’re not familiar with these concepts, you should read the relevant chapters in Concepts in Objective-C Programming.

See Also

The content in this document applies to Xcode 4.4 or later and assumes you are targeting either OS X v10.7 or later, or iOS 5 or later. For more information about Xcode, see Xcode Overview. For information on language feature availability, see Objective-C Feature Availability Index.

Objective-C apps use reference counting to determine the lifetime of objects. For the most part, the Automatic Reference Counting (ARC) feature of the compiler takes care of this for you. If you are unable to take advantage of ARC, or need to convert or maintain legacy code that manages an object’s memory manually, you should read Advanced Memory Management Programming Guide.

In addition to the compiler, the Objective-C language uses a runtime system to enable its dynamic and object-oriented features. Although you don’t usually need to worry about how Objective-C “works,” it’s possible to interact directly with this runtime system, as described by Objective-C Runtime Programming Guide and Objective-C Runtime Reference.

Copyright © 2014 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2014-09-17

Objective-C

объектно-ориентированный Apple, построенный на основе языка Mac OS X (Cocoa) и OpenStep. Также язык используется для Cocoa Touch).

Содержание

История [ ]

В начале 1980-х годов было популярно Clang и GCC (под управлением MinGW или Синтаксис языка [ ]

В языке Objective-C для обозначения объектов используется специальный тип id (это аналог типа Object в

В этой конструкции receiver является указателем на объект, а message — именем метода.

В отличие от языка C++, посылка сообщения nil’у является законной операцией, всегда возвращающей нулевое значение (nil).

Сообщение может также содержать параметры:

В этом примере именем метода (сообщения) является setOrigin. Обратите внимание, что каждому передаваемому аргументу соответствует ровно одно двоеточие. При этом в приведенном примере первый аргумент имеет метку (текст перед двоеточием), а второй — нет.

Язык Objective-C позволяет снабжать метками каждый аргумент, что заметно повышает читаемость кода и снижает вероятность передачи неправильного параметра. Именно такой стиль принят большинством разработчиков.

В этом примере в качестве имени сообщения выступает setWidth: height:.

Также поддерживается возможность передачи произвольного количества аргументов в сообщении:

Как и функции, сообщения могут возвращать значения, при этом в отличие от языка С, типом значения, возвращаемым по умолчанию, является id.

Результат одного сообщения можно сразу же использовать в другом сообщении:

Как уже говорилось, в Objective-C классы сами являются объектами. Основной задачей таких объектов (называемых class objects) является создание экземпляров данного класса (это очень похоже на паттерн Abstract Factory ).

При этом само имя класса играет двойную роль — с одной стороны оно выступает как тип данных (то есть он может быть использован для описания указателей на объекты данного класса). А с другой стороны имя класса может выступать в качестве объекта, которому посылается сообщение (в сообщениях имя класса может принимать участие только как receiver).

В языке Objective-C нет встроенного типа для булевских величин, поэтому обычно такой тип вводится искусственно. Далее для логических величин будет использоваться тип BOOL с возможными значениями YES и NO (как это делается в операционных системах NextStep, Mac OS X).

Первым достаточно серьёзным применением языка Objective-C было его использование в операционной системе NextStep. Для этой системы было написано большое количество различных классов на Objective-C, многие из которых до сих пор используются в Mac OS X.

Имена всех этих классов начинаются с префикса NS, обозначающего свою принадлежность к операционной системе NextStep. Сейчас они входят в библиотеку Foundation, на которой строятся приложения для OS X и iOS.

С одним из них — NSString — мы столкнемся в данной статье. Этот класс служит для работы со строками (при этом в качестве внутреннего представления символов используется Юникод).

Компилятор поддерживает данный тип, автоматически переводя конструкции вида @»my string» в

Для доступа к ней извне лучше всего воспользоваться

В скобках перечисляются атрибуты доступа к instance-переменной. Атрибуты разделяются на 3 основные группы.

Имена акцессора и мутатора

  • getter=getterName, используется для задания имени функции, используемой для извлечения значения instance-переменной.
  • setter=setterName, используется для задания имени функции, используемой для установки значения instance-переменной.

Ограничение чтения/записи

  • readwrite — у свойства есть как акцессор, так и мутатор. Является атрибутом по умолчанию.
  • readonly — у свойства есть только акцессор.

Эти атрибуты взаимоисключают друг друга. И последняя группа атрибуты мутатора.

    assign — для задания нового значения используется оператор присваивания. Используется только для

Автоматически созданный код — не всегда подходящее решение и может потребоваться создание методов доступа к instance-переменным вручную.

Язык часто критикуют за перегруженный, по сравнению с другими языками, синтаксис. Однако при этом нередко отмечается его более высокая читабельность.

Создание новых классов [ ]

Все ключевые слова языка Objective-C, отсутствующие в С, начинаются с символа @.

Как и в C++, описание класса и его реализация разделены (обычно описание помещается в заголовочные файлы с расширением h, а реализации — в файлы с расширением m).

Ниже приводится общая структура описания нового класса:

В версии runtime от Apple все классы имеют общего предка — класс NSObject, содержащий целый ряд важных методов.

Описание переменных ничем не отличается от описания переменных в структурах в языке С:

Если у вас не Apple, то скорее всего вместо NSObject вам потребуется Object (#import <objc/Object.h>).

Описания же методов заметно отличаются от принятых в C++ и очень сильно похожи на описания методов в языке Smalltalk.

Каждое описание начинается со знака плюс или минус. Знак плюс обозначает, что данный метод является методом класса (то есть его можно посылать только class object’у, а не экземплярам данного класса). Фактически методы класса являются аналогами статических методов в классах в языке C++.

Знак минус служит для обозначения методов объектов — экземпляров данного класса. Обратите внимание, что в Objective-C все методы являются

Обратите внимание, что имя метода может совпадать с именем instance-переменной данного класса (например, width и height).

Тип возвращаемого методом значения указывается в круглых скобках сразу же после знака плюс или минус (но перед названием метода). Если тип не указан, то считается, что возвращается значение типа id.

Далее идет имя метода, где после каждого двоеточия задается тип аргумента (в круглых скобках) и сам аргумент.

Язык Objective-C позволяет для аргументов метода задавать также один из следующих описателей — oneway, in, out, inout, bycopy и byref. Данные описатели служат для задания направления передачи данных и способа передачи. Их наличие заметно упрощает реализацию и работу с распределенными объектами (которые были реализованы в операционной системе NextStep к началу 90-х годов прошлого века).

Метод, принимающий произвольное количество параметров, может быть описан следующим образом:

Для подключения заголовочного файла в Objective-C вместо директивы #include используется

Реализация методов класса выглядит следующим образом:

Ниже приводится пример реализации методов класса Rect, описанного выше.

Как видно из примера выше, в методах доступны все instance-переменные. Однако, как и в C++, есть возможность управлять видимостью переменных (видимостью методов управлять нельзя) при помощи директив @private, @protected и @public (действующих полностью аналогично языку C++).

При этом к public переменным класса можно обращаться непосредственно, используя оператор -> (например objPtr -> fieldName).

Как работает механизм сообщений [ ]

Компилятор переводит каждую посылку сообщения, то есть конструкцию вида [object msg] в вызов функции objc_msgSend. Эта функция в качестве своего первого параметра принимает указатель на объект-получатель сообщения, в качестве второго параметра выступает т. н. селектор, служащий для идентификации посылаемого сообщения. Если в сообщении присутствуют аргументы, то они также передаются objc_msgSend как третий, четвёртый и т. д. параметры.

 

Каждый объект Objective-C содержит в себе атрибут isa — указатель на class object для данного объекта. class object автоматически создается компилятором и существует как один экземпляр, на который через isa ссылаются все экземпляры данного класса.

Каждый class object обязательно содержит в себе указатель на class object для родительского класса (superclass) и dispatch table. Последняя представляет собой словарь, сопоставляющий селекторам сообщений фактические адреса реализующих их методов (функций).

Таким образом, функция objc_msgSend ищет метод с данным селектором в dispatch table для данного объекта. Если его там нет, то поиск продолжается в dispatch table для его родительского класса и т. д.

Если метод (то есть соответствующая ему функция) находится, то осуществляется его вызов с передачей всех необходимых аргументов.

В противном случае объекту дается последний шанс обработать сообщение перед вызовом исключения — селектор сообщения вместе с параметрами «заворачивается» в специальный объект типа NSInvocation и объекту посылается сообщение forwardInvocation:, где в качестве параметра выступает объект класса NSInvocation.

Если объект поддерживает forwardInvocation:, то он может либо сам обработать посылаемое сообщение, либо переслать другому объекту для обработки:

Для ускорения поиска сообщений по dispatch table используется кэширование, позволяющее заметно снизить затраты на пересылку сообщений. Также облегчает поиск метода по таблицам использование так называемых селекторов вместо обычных имен. Обычно селектор представляет собой 32-битовую величину, позволяющую однозначно идентифицировать метод.

Тип селектора обозначается как SEL и существует ряд функций и конструкций, позволяющих осуществлять преобразование имени в селектор и обратно.

Так для получения селектора сообщения непосредственно по имени служит конструкция @selector():

Для получения селектора по строке символов (на этапе выполнения) и перевода селектора в строку служат функции NSSelectorFromString и NSStringFromSelector:

Мощная поддержка метаинформации в Objective-C позволяет прямо на этапе выполнения проверить поддерживает ли объект метод с данным селектором при помощи посылки ему сообщения respondsToSelector::

Довольно легко можно послать сообщение, соответствующее данному селектору (без аргументов, с одним, двумя или тремя аргументами), при помощи метода performSelector:, performSelector: withObject:, performSelector: withObject: withObject:, performSelector: withObject: withObject: withObject: и так далее.

Обратите внимание, что методы performSelector: всегда возвращают значение типа id.

Можно получить класс для данного объекта, послав ему сообщение class. Это сообщение возвращает класс в виде указателя на объект типа Class.

С другой стороны также можно легко получить соответствующий class object по имени класса:

Каждый метод фактически представляет собой функцию с двумя невидимыми аргументами — self и _cmd.

Первый является аналогом this, то есть указывает на сам объект — получатель сообщения. Второй — содержит селектор данного метода.

Аргумент self может использоваться для посылки сообщений самому себе, как например в следующем методе:

Однако кроме self есть ещё одна величина, которой могут посылаться сообщения — super. На самом деле super не является нормальной переменной — это всего лишь ещё одно обозначение для указателя на текущий объект. Но при посылке сообщения super поиск метода начинается не с dispatch table текущего объекта, а с dispatch table родительского объекта.

Таким образом, посылая сообщения super мы тем самым вызываем старые версии методов, переопределенные данным классом.

В языке Objective-C можно по селектору метода получить адрес реализующей его функции (именно как функции языка С).

Такая функция отличается от описания метода только вставкой в начало списка аргументов двух дополнительных параметров — указателя на сам объект (self) и селектора данного метода (_cmd).

Послав объекту сообщение methodForSelector: мы получаем в ответ адрес реализующей этот метод функции.

Это позволяет при необходимости многократного вызова одного и того же метода у заданного объекта полностью избежать всех расходов, связанных с пересылкой сообщений.

Протоколы [ ]

Язык Objective-C содержит полноценную поддержку протоколов (это аналог интерфейса в Java и абстрактного класса в C++, который также иногда принято называть интерфейсом). Протокол представляет собой просто список описаний методов. Объект реализует протокол, если он содержит реализации всех методов, описанных в протоколе.

Протоколы удобны тем, что позволяют выделять общие черты у разнородных объектов и передавать информацию об объектах заранее неизвестных классов.

Простейшее описание протокола выглядит следующим образом:

Так протокол Serializable может быть описан следующим образом:

Протокол может быть унаследован от произвольного количества других протоколов:

Точно также можно при описании класса задать не только родительский класс, но и набор протоколов:

Для проверки во время выполнения программы, поддерживается ли объектом заданный протокол объектов, можно использовать сообщение conformsToProtocol::

Кроме того, имя протокола (протоколов) можно использовать при описании переменных для явного указания компилятору о поддержке соответствующими объектами протокола (протоколов).

Так, если переменная myObject содержит указатель на объект заранее неизвестного класса, но при этом удовлетворяющий протоколам Serializable и Drawable, то её можно описать следующим образом:

Точно так же, если заранее известно, что myObject будет содержать указатель на объект, унаследованный от класса Shape и поддерживающего протокол Serializable, то эту переменную можно описать следующим образом:

Обратите внимание, что подобное описание служит только для сообщения компилятору, какие сообщения поддерживает данный объект.

Как и классы, все протоколы в Objective-C представлены при помощи объектов (класса Protocol):

Для предварительного объявления протоколов можно использовать следующую конструкцию:

Эта конструкция сообщает компилятору о том, что MyProto, Serializable и Drawable являются именами протоколов, которые будут определены позже.

Обработка исключений [ ]

В языке Objective-C поддерживается обработка исключений, очень похожая на используемую в языках C++ и Java.

Для этого служат директивы @try, @catch, @finally и @throw.

Для запуска исключения используется

Внутри @catch-блоков директива @throw может использоваться без параметра для повторного запуска обрабатываемого исключения (rethrowing exception).

Синхронизация [ ]

Язык Objective-C поддерживает синхронизацию для

В качестве мьютекса (т. е. параметра инструкции @synchronized) рекомендуется указывать объект, недоступный извне, поскольку это может привести к Создание и уничтожение объектов [ ]

В самом языке Objective-C нет специальных команд для создания и уничтожения объектов (подобных new и delete). Эта задача ложится на runtime-библиотеку и реализуется при помощи механизма посылки сообщений.

Реально используемой и наиболее широко распространенной схемой создания и уничтожения объектов в Objective-C является используемая в операционных системах NextStep и Mac OS X, которая и будет описана ниже.

Создание нового объекта разбивается на два шага — выделение памяти и инициализация объекта. Первый шаг реализуется методом класса alloc (реализованном в классе NSObject), который выделяет необходимое количество памяти (данный метод используется для выделения памяти не только для объектов класса NSObject, но и любого унаследованного от него класса). При этом в атрибут isa записывается указатель на class object соответствующего класса.

Обратите внимание, что сообщение alloc посылается class object-у требуемого класса и это сообщение возвращает указатель на выделенную под объект память.

Собственно сама инициализация объекта (то есть установка значений его instance-переменных, выделение дополнительных ресурсов и т. п.) осуществляется другими методами, по традиции имена этих методов начинаются с init. Обычно такое сообщение посылается сразу же после сообщение alloc, по адресу, возвращенному этим сообщением.

Приведённая выше конструкция является правильным способом создания объекта. Обратите внимание, что следующая конструкция может в ряде случаев не работать:

Это связано с тем, что для ряда классов метод init может вернуть совсем другой указатель (а не self).

Простейшими примерами того, когда может возникать подобная ситуация, являются

В ряде случаев оказывается удобным совместить выделение памяти и инициализацию объекта в один метод (класса), например в классе NSString есть ряд методов класса, возвращающих уже готовый (проинициализированный) объект:

Mac OS X (как и NextStep) для управления временем жизни объектов используют reference counting — каждый объект содержит внутри себя некоторый счетчик, при создании устанавливаемый в единицу.

Посылка объекту сообщения retain увеличивает значение этого счетчика на единицу (так все контейнерные классы библиотеки Foundation при помещении в них объекта, посылают ему сообщение retain).

Установившейся практикой является посылка объекту сообщения retain всеми, заинтересованными в нём сторонами (объектами), то есть если вы запоминаете ссылку на объект, то следует послать ему сообщение retain.

Когда объект перестает быть нужен, то ему просто посылается сообщение release.

Данное сообщение уменьшает значение счетчика на единицу и, если это значение стало меньше единицы, уничтожает данный объект.

Перед уничтожением объекта ему посылается сообщение dealloc, позволяющее объекту произвести свою деинициализацию. При этом это также является обычным сообщением и в нём Вы явно должны в конце вызвать унаследованную реализацию через [super dealloc].

Управление памятью [ ]

Базовые принципы [ ]

Управление памятью в Objective-C базируется на принципе «владения объектом». Основные правила управления памятью в Objective-C можно записать так:

  • Для получения объекта во владение необходимо вызвать метод, содержащий в названии «alloc», «new» либо «copy». Например, alloc, newObject, mutableCopy.
  • Для освобождения объекта, который был получен при помощи перечисленных выше функций, необходимо вызвать функцию «release» либо «autorelease». Во всех остальных случаях освобождение объекта не требуется.
  • Если полученный объект должен быть сохранен, необходимо либо стать его владельцем (вызвав retain), либо создать его копию (вызов, содержащий в названии «copy»).

Данные правила базируются на соглашении по именованию в Objective-C и, в то же время, сами являются основой этого соглашения.

Базовые принципы на практике [ ]

Предположим, в программе существует класс Company, у которого есть метод workers.

Рассмотрим небольшой пример использования такого класса:

Так как объект класса Company создается явно, он должен быть удален по окончании использования ([company release]). В то же время, название метода workers не говорит о том, кто должен удалять массив. В такой ситуации считается, что списком работников управляет объект Компания и его удалять не требуется.

Многие классы позволяют совместить создание объекта с его инициализацией при помощи методов, называемых convenience конструкторы; такие методы обычно называются +className… Можно предположить, что вызывающая сторона ответственна за управление временем жизни объекта, но подобное поведение противоречило бы соглашению по именованию в Objective-C.

В приведенном коде вызов [company release] недопустим, так как в данном случае управление временем жизни объекта должно осуществляться при помощи autorelease пула.

Ниже приводится пример корректной реализации метода company:

Вернемся к методу workers класса Company. Так как возвращается массив, временем жизни которого вызывающая сторона не управляет, реализация метода workers будет выглядеть приблизительно так:

Вызов autorelease добавляет объект copy в autorelease пул, вследствие чего возвращаемый объект получит сообщение release при удалении пула, в который он был добавлен. Если объекту, добавленному в autorelease пул, послать сообщение release самостоятельно, при удалении autorelease пула возникнет ошибка.

Возвращение объекта по ссылке

В ряде случаев объекты возвращаются по ссылке, например, метод класса NSData initWithContentsOfURL:options: error: в качестве параметра error принимает (NSError **)errorPtr. В этом случае так же работает соглашение по именованию, из которого следует, что явного запроса на владение объектом нет, соответственно, удалять его не требуется.

Когда счетчик ссылок объекта становится равным нулю, объект удаляется. При этом у объекта вызывается метод -(void)dealloc. Если в объекте содержатся какие-то данные, их необходимо удалить в этой функции.

После того, как всем переменным класса было послано сообщение release, необходимо вызвать метод dealloc базового класса. Это единственный случай, в котором допустим вызов метода dealloc напрямую.

Не существует никаких гарантий относительно времени вызова метода dealloc. В ряде случаев он вообще может не вызываться при завершении работы приложения для экономии времени, так как по завершении приложения ОС в любом случае освободит выделенную память. Соответственно, в методе dealloc не должно располагаться никаких методов, отвечающих за закрытие сокетов, файлов и т. п.

Autorelease pool [ ]

Autorelease пул используется для хранения объектов, которым будет послано сообщение release при удалении пула. Для того, чтобы добавить объект в autorelease пул, ему необходимо отправить сообщение autorelease.

В приложениях Cocoa autorelease пул всегда доступен по умолчанию. Для не-AppKit приложений необходимо создавать и управлять временем жизни autorelease пула самостоятельно.

Autorelease пул реализуется классом NSAutoreleasePool.

Удалить объекты из autorelease пула можно не только посредством отправки пулу сообщения release, но и с помощью сообщения drain. Поведение release и drain в среде с подсчетом ссылок идентично. Но в случае работы в GC среде drain вызывает функцию objc_collect_if_needed.

Autorelease пул в многопоточной среде

В Cocoa для каждого из потоков создается свой собственный autorelease пул. По завершении потока autorelease пул уничтожается и всем содержащимся в нём объектам посылается сообщение release.

Autorelease пул главного потока периодически пересоздается с целью уменьшения используемой памяти приложением. Во всех остальных потоках заниматься пересозданием autorelease пула необходимо самостоятельно, что крайне актуально для долгоживущих потоков.

Копирование объектов [ ]

Все объекты в Objective-C потенциально поддерживают копирование. Для того, чтобы создать копию объекта, необходимо вызвать метод copy, определённый в классе NSObject. Для создания копии будет вызван метод copyWithZone протокола NSCopying. NSObject не имеет поддержки этого протокола и при необходимости протокол NSCopying должен быть реализован в классах-наследниках.

Копии бывают двух видов: поверхностная копия (shallow copy) и полная копия (deep copy). Разница между этими копиями состоит в том, что при создании поверхностной копии копируются не данные, а ссылка на объект с данными. В случае полной копии копируется объект с данными.

Реализация копирования может различаться в зависимости от того, поддерживает ли класс-родитель протокол NSCopying. Пример кода для ситуации, когда родитель не реализует протокол NSCopying:

Если родитель поддерживает протокол NSCopying, реализация будет несколько иной: вызов allocWithZone заменяется на copyWithZone.

Для immutable объектов создание копии нецелесообразно, и можно ограничиться отправкой самому себе сообщения retain.

Категории [ ]

Язык Objective-C обладает возможностью добавлять новые методы к уже существующим классам. Аналогичной возможностью обладают языки

Реализация категории выглядит следующим образом:

С помощью категорий можно создавать свойства (property), которые будут доступны только для чтения другим классам и readwrite внутри своего класса:

Кроме всего прочего категории можно использовать для того, чтобы обеспечить реализацию классом какого-либо нового протокола, например:

Это избавляет от необходимости писать класс-адаптер PrintableString для NSString.

Class objects и Objective-C runtime [ ]

При компиляции программы на языке Objective-C компилятор для каждого введённого класса автоматически создаёт так называемый class object — полноценный объект, содержащий в себе всю информацию о данном классе, включая название, суперкласс, список методов и instance-переменных.

При этом такой объект является полноценным объектом, то есть ему можно посылать сообщения, передавать в качестве параметра.

Одной из особенностей class object’а является поддержка всех методов класса NSObject. То есть при отправке сообщения поиск по селектору сначала ведётся среди методов класса, и если метод не найден, поиск продолжается среди instance-методов класса NSObject.

Ещё одной особенностью является возможность инициализации class object’ов — в начале работы приложения каждому class object’у посылается сообщение (класса) initialize.

Это сообщение гарантированно посылается каждому class object’у, причём всего один раз и до того, как ему будет послано любое другое сообщение. Простейшим примером применения такого сообщения является реализация Singleton’ов — именно в методе initialize следует создать тот самый единственный экземпляр объекта и запомнить его в static-переменной.

Objective-C runtime от Apple содержит большое количество С-функций, служащих для работы с классами (непосредственно во время выполнения программы).

Наиболее интересными являются следующие:

Функция class_getInstanceMethod возвращает указатель на структуру (objc_method), описывающую заданный instance-метод данного класса.

Функция class_getClassMethod возвращает указатель на структуру (objc_method), описывающую заданный метод данного класса.

Функция class_nextMethodList возвращает один из списков методов для заданного класса. Приводимый ниже фрагмент кода позволяет перебрать все методы для данного класса.

Функция class_addMethods позволяет добавлять новые методы к заданному классу.

Функция class_removeMethods позволяет убирать методы из заданного класса.

Функция method_getNumberOfArguments Возвращает количество аргументов для заданного метода.

Функция method_getSizeOfArguments возвращает размер места на стеке, занимаемого всеми аргументами данного метода.

Функция method_getArgumentInfo возвращает информацию об одном из аргументов для заданного метода.

Функция class_getInstanceVariable возвращает информацию об instance-переменной класса в виде указателя на структуру objc_ivar.

Для кодирования информации о типах используется специальное строковое представление, однозначно сопоставляющее каждому типу данных некоторую строку. Явно получить такую строку для произвольного типа можно при помощи конструкции @encode ().

Разное [ ]

Официальный сайт Apple [1] — главный источник информации о языке. Форум разработчиков, примеры кода и полная версия документации доступны только зарегистрированным разработчикам.

Xcode — основное средство разработки на языке Objective-C. IDE поддерживает только Mac OS X и распространяется бесплатно через магазин приложений [2] и архивах списка рассылки [3] .

Проект [4] — попытка создания аналогов закрытых библиотек Foundation и AppKit, используемых в NextStep и Mac OS X . Исходный код библиотек написан на языке Objective-C и распространяется бесплатно. На сайте проекта доступны примеры использования языка и исходный код нескольких приложений.

Objective-C доступен практически в каждом дистрибутиве Windows используют эмуляторы среды POSIX (бесплатные):

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *