stringtranslate.com

Цель-C

Objective-C — это высокоуровневый объектно-ориентированный язык программирования общего назначения , который добавляет обмен сообщениями в стиле Smalltalk к языку программирования C [3] . Первоначально разработанный Брэдом Коксом и Томом Лавом в начале 1980-х годов, он был выбран NeXT для своей операционной системы NeXTSTEP . Из-за прямого происхождения Apple macOS от NeXTSTEP, [4] Objective-C был стандартным языком программирования, который использовался, поддерживался и продвигался Apple для разработки приложений macOS и iOS (через соответствующие API , Cocoa и Cocoa Touch ) до появления языка программирования Swift в 2014 году. [3] После этого его использование среди разработчиков постоянно сокращалось, и его часто называли «умирающим» языком. [5]

Программы Objective-C, разработанные для операционных систем сторонних производителей или не зависящие от API Apple, также могут быть скомпилированы для любой платформы , поддерживаемой GNU GCC или LLVM / Clang .

Программные файлы «обмена сообщениями/реализации» исходного кода Objective-C обычно имеют расширения имени файла .m , тогда как файлы «заголовка/интерфейса» Objective-C имеют расширения .h , такие же, как файлы заголовков C. Файлы Objective-C++ обозначаются расширением .mm .

История

Objective-C был создан в первую очередь Брэдом Коксом и Томом Лавом в начале 1980-х годов в их компании Productivity Products International (PPI) . [6]

Накануне создания своей компании оба познакомились со Smalltalk в 1981 году в Центре технологий программирования корпорации ITT. Самая ранняя работа над Objective-C относится примерно к этому времени. [7] Кокс был заинтригован проблемами истинного повторного использования в разработке программного обеспечения и программировании. Он понял, что такой язык, как Smalltalk, будет иметь неоценимое значение при создании сред разработки для разработчиков систем в ITT. Однако он и Том Лав также признали, что обратная совместимость с C имеет решающее значение в сфере телекоммуникаций ITT. [8]

Кокс начал писать препроцессор для C , чтобы добавить некоторые возможности Smalltalk . Вскоре у него была рабочая реализация объектно-ориентированного расширения языка C , которое он назвал «OOPC» (объектно-ориентированный прекомпилятор). [9] Лав была нанята компанией Schlumberger Research в 1982 году и получила возможность приобрести первую коммерческую копию Smalltalk-80, что еще больше повлияло на развитие их детища. Чтобы продемонстрировать возможность достижения реального прогресса, Кокс показал, что для создания взаимозаменяемых компонентов программного обеспечения действительно необходимо лишь несколько практических изменений в существующих инструментах. В частности, им нужно было гибко поддерживать объекты, поставлять их с удобным набором библиотек и позволять объединять код (и любые ресурсы, необходимые для кода) в один кроссплатформенный формат.

Лав и Кокс в конечном итоге сформировали PPI для коммерциализации своего продукта, который объединил компилятор Objective-C с библиотеками классов. В 1986 году Кокс опубликовал основное описание Objective-C в его первоначальном виде в книге Object-Oriented Programming, An Evolutionary Approach . Хотя он осторожно отметил, что проблема повторного использования заключается не только в том, что обеспечивает Objective-C, язык часто сравнивался с другими языками.

Популяризация через NeXT

В 1988 году NeXT лицензировала Objective-C у StepStone (новое название PPI, владельца торговой марки Objective-C) и расширила компилятор GCC для поддержки Objective-C. NeXT разработала библиотеки AppKit и Foundation Kit , на которых основан пользовательский интерфейс NeXTSTEP и Interface Builder. Хотя рабочие станции NeXT не имели большого влияния на рынке, эти инструменты получили широкую оценку в отрасли. Это привело к тому, что NeXT отказалась от производства аппаратного обеспечения и сосредоточилась на программных инструментах, продавая NeXTSTEP (и OPENSTEP) как платформу для индивидуального программирования.

Чтобы обойти условия GPL , NeXT изначально намеревалась поставлять интерфейс Objective-C отдельно, позволяя пользователю связать его с GCC для создания исполняемого файла компилятора. Хотя первоначально этот план был принят Ричардом М. Столлманом , этот план был отклонен после того, как Столлман проконсультировался с юристами GNU, и NeXT согласилась сделать Objective-C частью GCC. [10]

Работу по расширению GCC возглавил Стив Нарофф, перешедший в NeXT из StepStone. Изменения компилятора были доступны в соответствии с условиями лицензии GPL , но библиотеки времени выполнения — нет, что сделало вклад с открытым исходным кодом непригодным для использования широкой публикой. Это привело к тому, что другие стороны разработали такие библиотеки времени выполнения под лицензиями с открытым исходным кодом. Позже Стив Нарофф также внес основной вклад в работу Apple над созданием интерфейса Objective-C для Clang .

Проект GNU начал работу над своей свободной программной реализацией Cocoa под названием GNUstep , основанной на стандарте OpenStep . [11] Деннис Глаттинг написал первую среду выполнения GNU Objective-C в 1992 году. Среда выполнения GNU Objective-C, которая используется с 1993 года, разработана Крестеном Крабом Торупом, когда он был студентом университета в Дании . [ нужна ссылка ] Торуп также работал в NeXT с 1993 по 1996 год. [12]

Разработка Apple и Swift

После приобретения NeXT в 1996 году компания Apple Computer использовала OpenStep в своей тогдашней новой операционной системе Mac OS X. Сюда входили Objective-C, инструмент разработчика NeXT на основе Objective-C Project Builder и его инструмент проектирования интерфейсов Interface Builder . Оба позже были объединены в одно приложение Xcode . Большая часть текущего API Cocoa от Apple основана на объектах интерфейса OpenStep и является наиболее важной средой Objective-C, используемой для активной разработки.

На WWDC 2014 компания Apple представила новый язык Swift , который был охарактеризован как «Objective-C без C».

Синтаксис

Objective-C представляет собой тонкий слой поверх C и является «строгой надстройкой » C, что означает, что можно скомпилировать любую программу C с помощью компилятора Objective-C и свободно включать код языка C в класс Objective-C. [13] [14] [15] [16] [17] [18]

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

Сообщения

Модель объектно-ориентированного программирования Objective-C основана на передаче сообщений экземплярам объекта. В Objective-C метод не вызывается ; один отправляет сообщение . Это отличается от модели программирования в стиле Simula , используемой в C++ . Разница между этими двумя понятиями заключается в том, как выполняется код, на который ссылается имя метода или сообщения. В языке в стиле Simula имя метода в большинстве случаев привязывается компилятором к разделу кода в целевом классе. В Smalltalk и Objective-C цель сообщения определяется во время выполнения, при этом принимающий объект сам интерпретирует сообщение. Метод идентифицируется селектором или SEL — уникальным идентификатором для каждого имени сообщения, часто просто строкой с нулевым символом в конце , представляющей его имя — и разрешается в указатель метода C , реализующий его: IMP. [19] Следствием этого является то, что система передачи сообщений не имеет проверки типа. Объект, которому направляется сообщение — получатель , не гарантирует, что ответит на сообщение, а если нет, то он вызывает исключение. [20]

Для отправки метода сообщения объекту, на который указывает указатель obj, потребуется следующий код на C++ :

объект -> метод ( аргумент );

В Objective-C это записывается следующим образом:

[ метод объекта : аргумент ]; 

Вызов «метода» транслируется компилятором в семейство функций времени выполнения objc_msgSend(id self, SEL op, ...) . Различные реализации обрабатывают современные дополнения, такие как super . [21] В семействах GNU эта функция называется objc_msg_sendv , но она устарела в пользу современной системы поиска под objc_msg_lookup . [22]

Оба стиля программирования имеют множество сильных и слабых сторон. Объектно-ориентированное программирование в стиле Simula ( C++ ) допускает множественное наследование и более быстрое выполнение за счет использования привязки во время компиляции , когда это возможно, но по умолчанию не поддерживает динамическую привязку . Это также заставляет все методы иметь соответствующую реализацию, если они не являются абстрактными . Программирование в стиле Smalltalk, используемое в Objective-C, позволяет сообщениям оставаться нереализованными, а метод разрешается для его реализации во время выполнения. Например, сообщение может быть отправлено коллекции объектов, на которые, как ожидается, ответят только некоторые, не опасаясь возникновения ошибок во время выполнения. Передача сообщений также не требует определения объекта во время компиляции. Для вызова метода в производном объекте по-прежнему требуется реализация. (Дополнительные преимущества динамического (позднего) связывания см. в разделе динамической типизации ниже.)

Интерфейсы и реализации

Objective-C требует, чтобы интерфейс и реализация класса были в отдельно объявленных блоках кода. По соглашению разработчики помещают интерфейс в файл заголовка , а реализацию — в файл кода. Файлы заголовков, обычно имеющие суффикс .h, аналогичны файлам заголовков C, тогда как файлы реализации (методов), обычно имеющие суффикс .m, могут быть очень похожи на файлы кода C.

Интерфейс

Это аналогично объявлениям классов, используемым в других объектно-ориентированных языках, таких как C++ или Python.

Интерфейс класса обычно определяется в заголовочном файле. Общепринятым соглашением является название заголовочного файла после имени класса, например, Ball.h будет содержать интерфейс для класса Ball .

Объявление интерфейса принимает форму:

@interface  classname  : superclassname  { // переменные экземпляра } + classMethod1 ; + ( тип_возврата ) classMethod2 ; + ( return_type ) classMethod3: ( param1_type ) param1_varName ;    -  ( тип_возврата ) экземплярМетод1С1Параметр: ( тип_параметра1 ) имя_переменной_параметра1 ; -  ( return_type ) instanceMethod2With2Parameters: ( param1_type ) param1_varName param2_callName :( param2_type ) param2_varName ; @конец 

В приведенном выше примере знаки плюс обозначают методы класса или методы, которые можно вызывать в самом классе (не в экземпляре), а знаки минус обозначают методы экземпляра , которые можно вызывать только в конкретном экземпляре класса. Методы класса также не имеют доступа к переменным экземпляра .

Приведенный выше код примерно эквивалентен следующему интерфейсу C++ :

class имя класса : public superclassname { protected : // переменные экземпляра      public : // Функции класса (статические) static void * classMethod1 (); статический return_type classMethod2 (); статический return_type classMethod3 ( param1_type param1_varName );            // Функции экземпляра (члена) return_type instanceMethod1With1Parameter ( param1_type param1_varName ); return_type instanceMethod2With2Parameters ( param1_type param1_varName , param2_type param2_varName = default ); };          

Обратите внимание, что instanceMethod2With2Parameters:param2_callName: демонстрирует чередование сегментов селектора с выражениями аргументов, для которого нет прямого эквивалента в C/C++.

Типы возвращаемых значений могут быть любым стандартным типом C , указателем на общий объект Objective-C, указателем на определенный тип объекта, например NSArray *, NSImage * или NSString *, или указателем на класс, к которому принадлежит метод. (тип экземпляра). Тип возвращаемого значения по умолчанию — это общий идентификатор типа Objective-C .

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

-  ( void ) setRangeStart: ( int ) start end: ( int ) end ; - ( void ) importDocumentWithName: ( NSString * ) имя withSpecifiedPreferences : ( Preferences * ) prefs beforePage : ( int ) InsertPage ;      

Производной от определения интерфейса является категория , которая позволяет добавлять методы к существующим классам. [23]

Выполнение

Интерфейс объявляет только интерфейс класса, а не сами методы: фактический код записывается в файле реализации. Файлы реализации (методов) обычно имеют расширение .m, которое первоначально означало «сообщения». [24]

@implementation  имя класса +  ( return_type ) classMethod { // реализация } - ( return_type ) instanceMethod { // реализация } @end     

Методы пишутся с использованием объявлений их интерфейсов. Сравнение Objective-C и C:

-  ( int ) метод: ( int ) i { return [ self Square_root : i ]; }    
int function ( int i ) { return Square_root ( i ); }     

Синтаксис допускает псевдоименование аргументов .

-  ( void ) changeColorToRed: ( float ) красный зеленый: ( float ) зеленый синий: ( float ) синий { //... Реализация ... }    // Вызывается так: [ myColorchangeColorToRed : 5.0 green : 2.0 blue : 6.0 ] ;   

Внутренние представления метода различаются в разных реализациях Objective-C. Если myColor принадлежит классу Color , метод экземпляра -changeColorToRed:green:blue: может иметь внутреннюю метку _i_Color_changeColorToRed_green_blue . i означает метод экземпляра, к которому добавляются имена классов, а затем имена методов, а двоеточия заменяются на подчеркивания . Поскольку порядок параметров является частью имени метода, его нельзя изменить в соответствии со стилем кодирования или выражением, как в случае с параметрами с настоящими именами.

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

Создание экземпляра

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

Создание экземпляра с инициализатором по умолчанию без параметров:

MyObject * foo = [[ MyObject alloc ] init ];     

Создание экземпляра с помощью специального инициализатора:

MyObject * foo = [[ MyObject alloc ] initWithString : myString ];     

В случае, когда пользовательская инициализация не выполняется, вместо сообщений alloc-init часто можно использовать «новый» метод:

MyObject * foo = [ MyObject new ];    

Кроме того, некоторые классы реализуют инициализаторы методов класса. Подобно +new, они объединяют +allocи -init, но в отличие от +new, они возвращают автоматически выпущенный экземпляр. Некоторые инициализаторы методов класса принимают параметры:

MyObject * foo = [ объект MyObject ]; MyObject * bar = [ MyObject objectWithString : @"Википедия :)" ];        

Сообщение alloc выделяет достаточно памяти для хранения всех переменных экземпляра объекта, устанавливает для всех переменных экземпляра нулевые значения и превращает память в экземпляр класса; ни на каком этапе инициализации память не является экземпляром суперкласса.

Сообщение инициализации выполняет настройку экземпляра после его создания. Метод init часто записывается следующим образом:

-  ( идентификатор ) инициализация {  сам = [ супер инициализация ];    если ( сам ) {   // здесь выполняем инициализацию объекта } вернуть себя ; }

В приведенном выше примере обратите внимание на idтип возвращаемого значения. Этот тип означает «указатель на любой объект» в Objective-C (см. раздел «Динамическая типизация»).

Шаблон инициализатора используется для обеспечения правильной инициализации объекта его суперклассом до того, как метод init выполнит его инициализацию. Он выполняет следующие действия:

Недопустимый указатель объекта имеет значение nil ; условные операторы, такие как «if», рассматривают nil как нулевой указатель, поэтому код инициализации не будет выполнен, если [super init]будет возвращено значение nil. Если при инициализации произошла ошибка, метод init должен выполнить всю необходимую очистку, включая отправку сообщения «release» самому себе, и вернуть ноль , чтобы указать, что инициализация не удалась. Любая проверка таких ошибок должна выполняться только после вызова инициализации суперкласса, чтобы гарантировать, что уничтожение объекта будет выполнено правильно.

Если класс имеет более одного метода инициализации, только один из них («назначенный инициализатор») должен следовать этому шаблону; другие должны вызывать назначенный инициализатор вместо инициализатора суперкласса.

Протоколы

В других языках программирования их называют «интерфейсами».

Objective-C был расширен в NeXT , чтобы представить концепцию множественного наследования спецификации, но не реализации, посредством введения протоколов . Это шаблон, который можно реализовать либо как абстрактный базовый класс с множественным наследованием в C++ , либо как «интерфейс» (как в Java и C# ). Objective-C использует специальные протоколы, называемые неформальными протоколами, и протоколы, обеспечиваемые компилятором, называемые формальными протоколами .

Неформальный протокол — это список методов, которые класс может реализовать. Он указан в документации, поскольку в языке его нет. Неформальные протоколы реализуются как категория (см. ниже) в NSObject и часто включают дополнительные методы, которые, если они реализованы, могут изменить поведение класса. Например, класс текстового поля может иметь делегат , реализующий неформальный протокол с дополнительным методом для автоматического заполнения введенного пользователем текста. Текстовое поле определяет, реализует ли делегат этот метод (посредством отражения ), и если да, вызывает метод делегата для поддержки функции автозаполнения.

Формальный протокол аналогичен интерфейсу в Java, C# и Ada 2005 . Это список методов, которые любой класс может реализовать. Версии Objective-C до версии 2.0 требовали, чтобы класс реализовывал все методы в протоколе, который он объявляет принятым; компилятор выдаст ошибку, если класс не реализует каждый метод из объявленных протоколов. В Objective-C 2.0 добавлена ​​поддержка пометки определенных методов в протоколе как необязательные, и компилятор не будет принудительно реализовывать необязательные методы.

Класс должен быть объявлен для реализации этого протокола, чтобы можно было сказать, что он соответствует ему. Это можно обнаружить во время выполнения. Формальные протоколы не могут обеспечить никаких реализаций; они просто уверяют вызывающую сторону, что классы, соответствующие протоколу, будут предоставлять реализации. В библиотеке NeXT/Apple протоколы часто используются системой распределенных объектов для представления возможностей объекта, выполняющегося в удаленной системе.

Синтаксис

@protocol  NSLocking -  ( недействительная ) блокировка ; -  ( недействительно ) разблокировать ; @конец

означает, что существует абстрактная идея блокировки. Указав в определении класса, что протокол реализован,

@interface  NSLock  : NSObject < NSLocking > // ... @end 

экземпляры NSLock заявляют, что они предоставят реализацию двух методов экземпляра.

Динамическая типизация

Objective-C, как и Smalltalk, может использовать динамическую типизацию : объекту может быть отправлено сообщение, не указанное в его интерфейсе. Это может обеспечить повышенную гибкость, поскольку позволяет объекту «перехватывать» сообщение и отправлять его другому объекту, который может соответствующим образом ответить на сообщение, или аналогичным образом отправлять сообщение другому объекту. Такое поведение известно как пересылка сообщений или делегирование (см. ниже). В качестве альтернативы можно использовать обработчик ошибок, если сообщение не может быть перенаправлено. Если объект не пересылает сообщение, не отвечает на него или не обрабатывает ошибку, система генерирует исключение во время выполнения. [25] Если сообщения отправляются в nil (нулевой указатель объекта), они будут молча игнорироваться или вызывать общее исключение, в зависимости от параметров компилятора.

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

-  ( void ) setMyValue: ( id ) foo ;

В приведенном выше утверждении foo может относиться к любому классу.

-  ( void ) setMyValue : ( id <NSCopying> ) foo ; _

В приведенном выше утверждении foo может быть экземпляром любого класса, соответствующего протоколу NSCopying.

-  ( void ) setMyValue: ( NSNumber * ) foo ; 

В приведенном выше утверждении foo должен быть экземпляром класса NSNumber .

-  ( void ) setMyValue: ( NSNumber < NSCopying > * ) foo ; 

В приведенном выше утверждении foo должен быть экземпляром класса NSNumber и должен соответствовать протоколу NSCopying.

В Objective-C все объекты представлены как указатели, и статическая инициализация не допускается. Самый простой объект — это тип, на который указывает id ( objc_obj * ), который имеет только указатель isa , описывающий его класс. Другие типы из C, такие как значения и структуры, не изменяются, поскольку они не являются частью объектной системы. Это решение отличается от объектной модели C++, где структуры и классы объединены.

Пересылка

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

Среда выполнения Objective-C определяет пару методов в Object

Объекту, желающему реализовать пересылку, необходимо только переопределить метод пересылки новым методом, чтобы определить поведение пересылки. Метод действия Performv:: не нужно переопределять, поскольку этот метод просто выполняет действие на основе селектора и аргументов. Обратите внимание на тип — тип сообщений в Objective-C.SEL

Примечание. В OpenStep, Cocoa и GNUstep, широко используемых средах Objective-C, класс Object не используется . Метод класса NSObject используется для пересылки.- (void)forwardInvocation:(NSInvocation *)anInvocation

Пример

Вот пример программы, демонстрирующей основы переадресации.

Форвардер.h
#import <objc/Object.h>@interface  Forwarder  : Object  { id получателя ; // Объект, которому мы хотим переслать сообщение. }   // Методы доступа. -  ( id ) получателя ; -  ( id ) setRecipient: ( id ) _recipient ; @конец
Форвардер.м
#import "Форвардер.h"@implementation  Forwarder -  ( retval_t ) вперед: ( SEL ) sel args: ( arglist_t ) args { /*  * Проверьте, действительно ли получатель отвечает на сообщение.  * Это может быть желательно, а может и нет, например, если получатель  *, в свою очередь, не отвечает на сообщение, он может выполнить пересылку  * самостоятельно.  */ if ([ получатель отвечаетToSelector : sel ]) { return [ производительность получателя : sel args : args ]; } else { return [ собственная ошибка : «Получатель не отвечает» ]; } }                  -  ( id ) setRecipient: ( id ) _recipient { [ автовыпуск получателя ]; получатель = [ _recipient сохранить ]; вернуть себя ; }         -  ( id ) получатель { возврат получателя ; } @конец   
Получатель.h
#import <objc/Object.h>// Простой объект Получатель. @interface  Получатель  : Объект -  ( id ) привет ; @конец
Получатель.м
#import "Получатель.h"@implementation  Получатель-  ( id ) hello { printf ( «Получатель передает привет! \n » );   вернуть себя ; } @конец
main.m
#import "Forwarder.h" #import "Recipient.h"int main ( void ) { Форвардер * Форвардер = [ Новый экспедитор ]; Получатель * получатель = [ Новый получатель ];             [ пересылающий setRecipient : получатель ]; // Устанавливаем получателя. /*  * Обратите внимание, что сервер пересылки не отвечает на сообщение приветствия! Он будет  * переслан. Все нераспознанные методы будут перенаправлены  *получателю  * (если получатель на них ответит, как написано в Forwarder)  */ [ forwarder hello ];      [ выпуск получателя ]; [ выпуск экспедитора ];    вернуть 0 ; } 

Примечания

При компиляции с использованием gcc компилятор сообщает:

$ gcc  -x  Objective-c  -Wno-import  Forwarder.m  Recipient.m  main.m  -lobjc main.m: В функции `main': main.m:12: предупреждение: `Forwarder' не отвечает на `hello' $

Компилятор сообщает о сделанном ранее замечании, что Forwarder не отвечает на сообщения приветствия. В этом случае можно безопасно игнорировать предупреждение, поскольку пересылка реализована. Запуск программы дает такой вывод:

$ ./a.out Получатель передает привет!

Категории

При разработке Objective-C одной из основных проблем была удобство сопровождения больших баз кода. Опыт мира структурированного программирования показал, что одним из основных способов улучшения кода является его разбиение на более мелкие части. Objective-C заимствовал и расширил концепцию категорий из реализаций Smalltalk, чтобы облегчить этот процесс. [26]

Более того, методы внутри категории добавляются в класс во время выполнения . Таким образом, категории позволяют программисту добавлять методы к существующему классу ( открытому классу ) без необходимости перекомпиляции этого класса или даже доступа к его исходному коду. Например, если система не содержит средства проверки орфографии в своей реализации String, ее можно добавить без изменения исходного кода String.

Методы внутри категорий становятся неотличимыми от методов класса при запуске программы. Категория имеет полный доступ ко всем переменным экземпляра внутри класса, включая частные переменные.

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

В других языках эту функцию пытались добавить разными способами. TOM продвинул систему Objective-C на шаг дальше и позволил также добавлять переменные. Вместо этого в других языках используются решения на основе прототипов , наиболее заметным из которых является Self .

Языки C# и Visual Basic.NET реализуют внешне схожие функциональные возможности в виде методов расширения , но у них нет доступа к закрытым переменным класса. [27] Ruby и некоторые другие языки динамического программирования называют этот метод « обезьяньим исправлением ».

Logtalk реализует концепцию категорий (как объектов первого класса), которая включает в себя функциональность категорий Objective-C (Категории Logtalk также можно использовать в качестве детализированных единиц композиции при определении, например, новых классов или прототипов; в частности, категория Logtalk может быть практически импортированы любым количеством классов и прототипов).

Пример использования категорий

В этом примере создается класс Integer , сначала определяя базовый класс, в котором реализованы только методы доступа , и добавляя две категории: Arithmetic и Display , которые расширяют базовый класс. Хотя категории могут получать доступ к закрытым членам данных базового класса, зачастую хорошей практикой является доступ к этим закрытым членам данных через методы доступа, что помогает сохранять категории более независимыми от базового класса. Реализация таких методов доступа является одним из типичных применений категорий. Другой способ — использовать категории для добавления методов в базовый класс. Однако не считается хорошей практикой использовать категории для переопределения подклассов, также известное как исправление обезьян . Неформальные протоколы реализованы как категория базового класса NSObject . По соглашению файлы, содержащие категории, расширяющие базовые классы, будут называться BaseClass+ExtensionClass.h .

Целое число.h
#import <objc/Object.h>@interface  Integer  : Object  { int целое число ; }  -  ( целое ) целое число ; -  ( id ) целое число: ( int ) _integer ; @конец
Целое число.м
#import "Целое число.h"@implementation  Целое число -  ( int )  целое число { возвращаемое целое число ; }   -  ( id )  целое число: ( int ) _integer { целое число = _integer ; вернуть себя ; } @конец        
Целое число+Арифметика.h
#import "Целое число.h"@interface  Integer  (Арифметика) -  ( id )  add: ( Integer * ) addend ; - ( id ) sub: ( Целое число * ) вычитаемое ; @конец        
Целое число+Арифметика.м
#import "Целое число+Арифметика.h"@implementation  Целое число  (арифметика) -  ( id )  add: ( Целое число * ) addend { return [ собственное целое число : [ собственное целое число ] + [ добавить целое число ]]; }            -  ( id )  sub: ( Целое число * ) вычитаемое { return [ целое число самого себя : [ целое число самого себя ] - [ вычитаемое целое число ]]; } @конец            
Целое число+Display.h
#import "Целое число.h"@interface  Integer  (Display)  ( id )  showstars ; -  ( id )  шоуинт ; @конец
Целое число+Display.m
# импортируем "Integer+Display.h"@implementation  Integer  (Display) -  ( id )  showstars { int i , x = [ self целое число ]; for ( я знак равно 0 ; я < x ; я ++ ) { printf ( "*" ); } printf ( " \n " );                    вернуть себя ; } -  ( id )  showint { printf ( "%d \n " , [ self целое число ]);     вернуть себя ; } @конец 
main.m
#import "Целое число.h"#import "Целое число+Арифметика.h"#import "Целое число+Display.h"int main ( void ) {   Целое число * num1 = [ Новое целое число ], * num2 = [ Новое целое число ];         интервал х ;  printf ( "Введите целое число: " ); scanf ( "%d" , & x );  [ целое число num1 : x ];  [ число1 шоузвезд ];  printf ( "Введите целое число: " ); scanf ( "%d" , & x );  [ целое число num2 : x ];  [ число2 шоустаров ];  [ число1 добавить : число2 ];  [ показать номер1 ];  вернуть 0 ; }

Примечания

Компиляцию выполняют, например:

$ gcc  -x  Objective-c  main.m  Integer.m  Integer+Arithmetic.m  Integer+Display.m  -lobjc

Можно поэкспериментировать, опустив #import "Integer+Arithmetic.h"(строку 2) и (строку 21) и опустив Integer+Arithmetic.m при компиляции. Программа все равно будет работать. Это означает, что при необходимости можно комбинировать добавленные категории; если категории не нужны какие-то возможности, ее просто нельзя скомпилировать.[num1 add:num2]

позирует

Objective-C позволяет классу полностью заменять другой класс в программе. Говорят, что заменяющий класс «выдает себя за» целевой класс.

Позирование класса было объявлено устаревшим в Mac OS X v10.5 и недоступно в 64-разрядной среде выполнения. Похожая функциональность может быть достигнута с помощью перестановки методов в категориях, при которой реализация одного метода заменяется реализацией другого, имеющего ту же сигнатуру.

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

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

Например,

@interface  CustomNSApplication  : NSApplication @end@implementation  CustomNSApplication -  ( void )  setMainMenu: ( NSMenu * ) меню { // делаем что-то с меню } @end    class_poseAs ([ класс CustomNSApplication ], [ класс NSApplication ]);    

Это перехватывает каждый вызов setMainMenu к NSApplication.

#Импортировать

В языке C #includeдиректива предварительной компиляции всегда вызывает вставку содержимого файла в исходный код в этот момент. В Objective-C есть #importэквивалентная директива, за исключением того, что каждый файл включается только один раз в единицу компиляции, что устраняет необходимость включения защиты .

GCC-компиляция Linux

// ФАЙЛ: hello.m #import <Foundation/Foundation.h> int main ( int argc , const char * argv []) { /* моя первая программа на Objective-C */ NSLog ( @"Hello, World! \ н " ); вернуть 0 ; }           
$ # Компиляция командной строки для компилятора gcc и MinGW: $ gcc \  $ ( gnustep-config --objc-flags ) \ -o hello \ hello.m \ -L /GNUstep/System/Library/Libraries \ -lobjc \ -lgnustep -база              $ ./привет

Другие особенности

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

Языковые варианты

Цель-C++

Objective-C++ — это вариант языка, принятый интерфейсом GNU Compiler Collection и Clang , который может компилировать исходные файлы, использующие комбинацию синтаксиса C++ и Objective-C. Objective-C++ добавляет к C++ расширения, которые Objective-C добавляет к C. Поскольку ничего не делается для унификации семантики различных функций языка, применяются определенные ограничения:

Цель-C 2.0

На Всемирной конференции разработчиков 2006 года Apple объявила о выпуске «Objective-C 2.0», версии языка Objective-C, включающей «современную сборку мусора, улучшения синтаксиса, [30] улучшения производительности во время выполнения, [31] и 64- битовая поддержка». Mac OS X v10.5 , выпущенная в октябре 2007 года, включала компилятор Objective-C 2.0. GCC 4.6 поддерживает множество новых функций Objective-C, таких как объявленные и синтезированные свойства, точечный синтаксис, быстрое перечисление, дополнительные методы протокола, атрибуты метода/протокола/класса, расширения классов и новый API среды выполнения GNU Objective-C. [32]

Название Objective-C 2.0 представляет собой прорыв в системе управления версиями языка, поскольку последней версией Objective-C для NeXT была «objc4». [33] Это название проекта было сохранено в последней версии устаревшего исходного кода среды выполнения Objective-C в Mac OS X Leopard (10.5). [34]

Вывоз мусора

В Objective-C 2.0 предусмотрен дополнительный консервативный сборщик мусора , работающий по поколениям . При запуске в режиме обратной совместимости среда выполнения превращала операции подсчета ссылок , такие как «сохранение» и «освобождение», в пустые операции . Когда сборка мусора была включена, все объекты подвергались сборке мусора. Обычные указатели C могут быть квалифицированы с помощью «__strong», чтобы также запускать базовые перехваты компилятора с барьером записи и, таким образом, участвовать в сборке мусора. [35] Также была предусмотрена слабая подсистема обнуления, так что указатели, помеченные как «__weak», обнуляются при сборе объекта (или, проще говоря, памяти GC). Сборщик мусора не существует в реализации iOS Objective-C 2.0. [36] Сбор мусора в Objective-C выполняется в фоновом потоке с низким приоритетом и может останавливаться при возникновении пользовательских событий, чтобы обеспечить оперативность взаимодействия с пользователем. [37]

Сбор мусора был объявлен устаревшим в Mac OS X v10.8 в пользу автоматического подсчета ссылок (ARC). [38] Objective-C на iOS 7 , работающем на ARM64 , использует 19 бит из 64-битного слова для хранения счетчика ссылок в виде помеченных указателей . [39] [40]

Характеристики

В Objective-C 2.0 представлен новый синтаксис для объявления переменных экземпляра как свойств с дополнительными атрибутами для настройки генерации методов доступа. Свойства в некотором смысле являются общедоступными переменными экземпляра; то есть объявление переменной экземпляра как свойства предоставляет внешним классам доступ (возможно, ограниченный, например, только для чтения) к этому свойству. Свойство может быть объявлено как «только для чтения» и ему может быть предоставлена ​​семантика хранения, такая как assign, copyили retain. По умолчанию считаются свойства atomic, что приводит к блокировке, предотвращающей одновременный доступ к ним нескольких потоков. Свойство можно объявить как nonatomic, что снимает эту блокировку.

@interface  Person  : NSObject  { @public NSString * name ; @private int age ; }    @property ( копия ) NSString * name ; @property ( только для чтения ) int age ;    -  ( id ) initWithAge: ( int ) age ; @конец

Свойства реализуются с помощью ключевого @synthesizeслова, которое генерирует методы получения (и установки, если они не доступны только для чтения) в соответствии с объявлением свойства. В качестве альтернативы методы получения и установки должны быть реализованы явно, или @dynamicможно использовать ключевое слово, чтобы указать, что методы доступа будут предоставлены другими способами. При компиляции с использованием clang 3.1 или выше все свойства, которые не объявлены явно с помощью @dynamic, не отмечены readonlyили не имеют полностью реализованных пользователем методов получения и установки, будут автоматически неявно @synthesize'd.

@implementation  Человек @synthesize имя ; -  ( id ) initWithAge: ( int ) initAge { self = [ super init ]; if ( self ) { // ПРИМЕЧАНИЕ: прямое присвоение переменной экземпляра, а не установка свойства age = initAge ; } Вернуть себя ; }               -  ( int ) age { возврат возраста ; } @конец   

Доступ к свойствам можно получить, используя традиционный синтаксис передачи сообщений, точечную нотацию или, в кодировании ключ-значение, по имени с помощью методов «valueForKey:»/»setValue:forKey:».

Person * aPerson = [[ Person alloc ] initWithAge : 53 ]; персона . имя = @"Стив" ; // ПРИМЕЧАНИЕ: в записи через точку используется синтезированный установщик, // эквивалентный [aPerson setName: @"Steve"]; NSLog ( @"Доступ по сообщению (%@), точечная запись(%@), имя свойства(% @) и " "прямой доступ к переменной экземпляра(% @)" , [ aPerson name ], aPerson . name , [ aPerson valueForKey : @"name" ], aPerson -> name );                  

Чтобы использовать точечную нотацию для вызова средств доступа к свойствам в методе экземпляра, следует использовать ключевое слово «self»:

-  ( void ) submitMyselfWithProperties: ( BOOL ) useGetter { NSLog ( @"Привет, меня зовут %@." , ( useGetter ? self . name : name )); // ПРИМЕЧАНИЕ: доступ к методу получения или доступ к ivar }        

Свойства класса или протокола могут подвергаться динамическому анализу .

интервал я ; ИНТ PropertyCount = 0 ; objc_property_t * propertyList = class_copyPropertyList ([ класс aPerson ], & propertyCount );         for ( я = 0 ; я < propertyCount ; я ++ ) { objc_property_t * thisProperty = propertyList + я ; const char * propertyName = property_getName ( * thisProperty ); NSLog ( @"У человека есть свойство: '%s'" , propertyName ); }                     

Нехрупкие переменные экземпляра

Objective-C 2.0 предоставляет устойчивые переменные экземпляра, если они поддерживаются средой выполнения (т. е. при создании кода для 64-разрядной macOS и всех iOS). В современной среде выполнения к доступу к переменным экземпляра добавляется дополнительный уровень косвенности, позволяющий динамическому компоновщику корректировать макет экземпляра во время выполнения. Эта функция позволяет внести два важных улучшения в код Objective-C:

Быстрое перечисление

Вместо использования объекта или индексов NSEnumerator для перебора коллекции Objective-C 2.0 предлагает синтаксис быстрого перечисления. В Objective-C 2.0 следующие циклы функционально эквивалентны, но имеют разные характеристики производительности.

// Использование NSEnumerator NSEnumerator * enumerator = [ thePeople objectEnumerator ]; Человек * р ;     while (( p = [ перечислитель nextObject ]) != nil ) { NSLog ( @"%@ исполнилось %i лет." , [ p name ], [ p age ]); }            
// Использование индексов for ( int i = 0 ; i < [ thePeople count ]; i ++ ) { Person * p = [ thePeople objectAtIndex : i ]; NSLog ( @"%@ %i лет." , [ имя страницы ] , [ возраст страницы ]); }                    
// Использование быстрого перечисления for ( Person * p in thePeople ) { NSLog ( @"%@ %i лет." , [ p name ], [ p age ]); }          

Быстрое перечисление генерирует более эффективный код, чем стандартное перечисление, поскольку вызовы методов для перечисления объектов заменяются арифметикой указателей с использованием протокола NSFastEnumeration. [41]

Расширения классов

Расширение класса имеет тот же синтаксис, что и объявление категории без имени категории, а объявленные в нем методы и свойства добавляются непосредственно в основной класс. В основном он используется как альтернатива категории для добавления методов в класс без объявления их в общедоступных заголовках, с тем преимуществом, что для расширений класса компилятор проверяет, действительно ли реализованы все объявленные в частном порядке методы. [42]

Последствия для развития какао

Все приложения Objective-C, разработанные для macOS, в которых используются вышеуказанные улучшения Objective-C 2.0, несовместимы со всеми операционными системами до версии 10.5 (Leopard). Поскольку быстрое перечисление не создает точно такие же двоичные файлы, как стандартное перечисление, его использование приведет к сбою приложения в Mac OS X версии 10.4 или более ранней.

Блоки

Blocks — это нестандартное расширение для Objective-C (а также C и C++ ), которое использует специальный синтаксис для создания замыканий . Блоки поддерживаются только в Mac OS X 10.6 «Snow Leopard» или новее, iOS 4 или новее, а также GNUstep с libobjc2 1.7 и компиляцией с помощью clang 3.1 или новее. [43]

#include <stdio.h> #include <Block.h> typedef int ( ^ IntBlock )();    IntBlock MakeCounter ( int start , int приращение ) { __block int i = start ;           return Block_copy ( ^ { int ret = i ; i += приращение ; return ret ; });             }int main ( void ) { IntBlock mycounter = MakeCounter ( 5 , 2 ); printf ( "Первый вызов: %d \n " , mycounter ()); printf ( "Второй вызов: %d \n " , mycounter ()); printf ( "Третий вызов: %d \n " , mycounter ());              /* поскольку он был скопирован, его также необходимо выпустить */ Block_release ( mycounter );  вернуть 0 ; } /* Вывод:  Первый вызов: 5  Второй вызов: 7  Третий вызов: 9 */ 

Современный Objective-C

Со временем Apple добавила в Objective 2.0 некоторые дополнительные функции. Дополнения касаются только «компилятора Apple LLVM », т.е. интерфейса clang языка. Как ни странно, управление версиями, используемое Apple, отличается от управления версиями LLVM; обратитесь к Xcode § Версии Toolchain для перевода на номера версий LLVM с открытым исходным кодом. [44]

Автоматический подсчет ссылок

Автоматический подсчет ссылок (ARC) — это функция времени компиляции, которая избавляет программистов от необходимости вручную управлять счетчиками сохранения с помощью retainи release. [45] В отличие от сборки мусора , которая происходит во время выполнения, ARC устраняет накладные расходы отдельного процесса, управляющего счетчиками сохранения. ARC и ручное управление памятью не являются взаимоисключающими; программисты могут продолжать использовать код, не поддерживающий ARC, в проектах с поддержкой ARC, отключив ARC для отдельных файлов кода. Xcode также может попытаться автоматически обновить проект до ARC.

ARC был представлен в LLVM 3.0. Это соответствует Xcode 4.2 (2011) или компилятору Apple LLVM 3.0. [46]

Литералы

Среды выполнения NeXT и Apple Obj-C уже давно включают краткий способ создания новых строк с использованием буквального синтаксиса @"a new string"или перехода к константам CoreFoundation kCFBooleanTrueи kCFBooleanFalsefor NSNumberс логическими значениями. Использование этого формата избавляет программиста от необходимости использовать более длинные initWithStringили аналогичные методы при выполнении определенных операций.

При использовании компилятора Apple LLVM 4.0 (Xcode 4.4) или более поздней версии массивы, словари и числа ( NSArray, NSDictionary, NSNumberклассы) также можно создавать с использованием буквального синтаксиса вместо методов. [47] (Компилятор Apple LLVM 4.0 транслируется в LLVM с открытым исходным кодом и Clang 3.1.) [48]

Пример без литералов:

NSArray * myArray = [ NSArray arrayWithObjects : объект1 , объект2 , объект3 , ноль ]; NSDictionary * myDictionary1 = [ NSDictionary словарьWithObject : someObject forKey : @"key" ]; NSDictionary * myDictionary2 = [ NSDictionary словарьWithObjectsAndKeys : object1 , key1 , object2 , key2 , nil ]; NSNumber * myNumber = [ NSNumber numberWithInt : myInt ]; NSNumber * mySumNumber = [ NSNumber numberWithInt : ( 2 + 3 )]; NSNumber * myBoolNumber = [ NSNumber numberWithBool : ДА ];                              

Пример с литералами:

NSArray * myArray = @[ объект1 , объект2 , объект3 ] ; NSDictionary * myDictionary1 = @{ @"key" : someObject } ; NSDictionary * myDictionary2 = @{ key1 : object1 , key2 : object2 } ; NSNumber * myNumber = @( myInt ) ; NSNumber * mySumNumber = @( 2 + 3 ) ; NSNumber * myBoolNumber = @YES ; NSNumber * myIntegerNumber = @8 ;                                  

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

Подписка

При использовании компилятора Apple LLVM 4.0 или более поздней версии массивами и словарями ( NSArrayи NSDictionaryклассами) можно управлять с помощью индексации. [47] Подписка может использоваться для извлечения значений из индексов (массив) или ключей (словарь), а с изменяемыми объектами также может использоваться для присвоения объектам индексов или ключей. В коде индексация представлена ​​с помощью скобок [ ]. [49]

Пример без подписки:

идентификатор объекта1 = [ someArray objectAtIndex : 0 ]; id object2 = [ someDictionary objectForKey : @"key" ]; [ someMutableArray replaceObjectAtIndex : 0 withObject : object3 ]; [ someMutableDictionary setObject : object4 forKey : @"key" ];            

Пример с подпиской:

идентификатор объекта1 = someArray [ 0 ]; id object2 = someDictionary [ @"key" ]; someMutableArray [ 0 ] = object3 ; someMutableDictionary [ @"key" ] = object4 ;          

«Современный» синтаксис Objective-C (1997 г.)

После покупки NeXT компанией Apple были предприняты попытки сделать этот язык более приемлемым для программистов, более знакомых с Java , чем со Smalltalk. Одной из таких попыток было введение того, что в то время называлось «современным синтаксисом» для Objective-C [50] (в отличие от текущего «классического» синтаксиса). В поведении не произошло никаких изменений, это был просто альтернативный синтаксис. Вместо написания вызова метода, например

 объект = [[ MyClass alloc ] init ]; [ объект firstLabel : param1 SecondLabel : param2 ];         

Вместо этого было написано как

 объект = ( MyClass . alloc ). в этом ; объект . метки ( параметр1 , параметр2 );       

Аналогично, декларации пошли от формы

 - ( void ) firstLabel : ( int ) param1 SecondLabel : ( int ) param2 ;    

к

 - ( void ) метки ( int param1 , int param2 );       

Этот «современный» синтаксис больше не поддерживается в текущих диалектах языка Objective-C.

мулле-объект

Проект mulle-objc — это еще одна повторная реализация Objective-C. Он поддерживает компиляторы GCC или Clang / LLVM в качестве бэкэндов. Он отличается от других сред выполнения с точки зрения синтаксиса, семантики и совместимости с ABI. Он поддерживает Linux, FreeBSD и Windows.

Портативный компилятор объектов

Помимо реализации GCC / NeXT / Apple , которая добавила несколько расширений к исходной реализации Stepstone , также существует еще одна бесплатная реализация Objective-C с открытым исходным кодом, называемая Portable Object Compiler. [51] Набор расширений, реализованных портативным компилятором объектов, отличается от реализации GCC/NeXT/Apple; в частности, он включает блоки типа Smalltalk для Objective-C, но в нем отсутствуют протоколы и категории — две функции, широко используемые в OpenStep и его производных и родственниках. В целом POC представляет собой более старую стадию эволюции языка, предшествовавшую появлению NeXT, что примерно соответствует книге Брэда Кокса 1991 года.

Он также включает в себя библиотеку времени выполнения под названием ObjectPak, которая основана на оригинальной библиотеке Cox ICPak101 (которая, в свою очередь, является производной от библиотеки классов Smalltalk-80) и весьма радикально отличается от OpenStep FoundationKit.

ГЕОС Цель-C

Система PC GEOS использовала язык программирования, известный как GEOS Objective-C или goc ; [52] Несмотря на сходство названий, эти два языка похожи только по общей концепции и использованию ключевых слов со знаком @.

Кланг

Компилятор Clang , являющийся частью проекта LLVM , реализует Objective-C и другие языки. После того, как GCC 4.3 (2008 г.) перешел на GPLv3, Apple отказалась от нее в пользу clang, компилятора, который у нее больше юридических полномочий для модификации. В результате многие современные функции языка Objective-C поддерживаются только Clang.

Схема управления версиями Apple для ее «компилятора LLVM» на основе clang отличается от системы управления версиями LLVM с открытым исходным кодом. См. перевод в Xcode § Toolchain версии [44].

GNU, GNUstep и WinObjC

Проект GNU уже давно интересуется платформой для переноса программ NeXT и Obj-C. Журнал изменений каталога libobjc в GCC предполагает, что он существовал до 1998 года (GCC 2.95), а его README дополнительно указывает на переписывание в 1993 году (GCC 2.4). [53]

Исходный код интерфейса NeXT был выпущен, поскольку он был создан как часть GCC, выпущена общественная лицензия GNU , которая обязывает тех, кто создает производные работы, делать это. [ когда? ] Apple продолжила эту традицию, выпустив форк GCC до версии 4.2.1, после чего отказались от компилятора. Сопровождающие GCC приняли изменения, но не вложили много средств в поддержку новых функций, таких как язык Objective-C 2.0. [33] : Какой компилятор 

Разработчики GNUstep, заинтересованные в новом языке, в 2009 году выделили GCC libobjc в независимый от GCC проект под названием libobjc2 . Они также организовали использование среды выполнения с Clang, чтобы воспользоваться преимуществами нового синтаксиса языка. [33] : Какой компилятор  GCC в то же время продвигался медленно, но в GCC 4.6.0 (2011) они также перешли на Objective-C 2.0 в своей libobjc. [32] [54] Документация GNUstep предполагает, что реализации GCC по-прежнему не хватает поддержки блоков, нехрупких переменных и нового ARC. [33] : Какая среда выполнения 

В 2015 году Microsoft превратила libobjc2 в часть WinObjC , моста iOS для универсальной платформы Windows . В сочетании с собственной реализацией Cocoa Touch и базовыми API проект позволяет повторно использовать код приложения iOS внутри приложений UWP. [55]

В Windows инструменты разработки Objective-C доступны для загрузки на веб-сайте GNUStep. Система разработки GNUStep состоит из следующих пакетов: GNUstep MSYS System, GNUstep Core, GNUstep Devel, GNUstep Cairo, ProjectCenter IDE (похож на Xcode, но не такой сложный), Gorm (построитель интерфейсов, аналогичный построителю Xcode NIB). Эти бинарные установщики не обновлялись с 2016 года [56] , поэтому было бы лучше просто установить их путем сборки под Cygwin или MSYS2 .

Использование библиотеки

Objective-C сегодня часто используется в тандеме с фиксированной библиотекой стандартных объектов (часто называемой «набором» или «фреймворком»), такими как Cocoa , GNUstep или ObjFW. Эти библиотеки часто поставляются вместе с операционной системой: библиотеки GNUstep часто поставляются с дистрибутивами на базе Linux , а Cocoa — с macOS. Программист не обязан наследовать функциональность существующего базового класса (NSObject/OFObject). Objective-C позволяет объявлять новые корневые классы, которые не наследуют существующие функции. Первоначально среды программирования на основе Objective-C обычно предлагали класс Object в качестве базового класса, от которого наследовались почти все остальные классы. С появлением OpenStep компания NeXT создала новый базовый класс под названием NSObject, который предлагал дополнительные функции по сравнению с Object (например, акцент на использовании ссылок на объекты и подсчете ссылок вместо необработанных указателей). Почти все классы в Cocoa наследуются от NSObject.

Переименование не только позволило дифференцировать новое поведение классов по умолчанию в API OpenStep, но и позволило коду, использующему Object — исходный базовый класс, используемый в NeXTSTEP (и, более или менее, в других библиотеках классов Objective-C), — сосуществовать в одной среде выполнения с кодом, использующим NSObject (с некоторыми ограничениями). Введение двухбуквенного префикса также стало упрощенной формой пространств имен, которой нет в Objective-C. Использование префикса для создания неофициального идентификатора упаковки стало неофициальным стандартом кодирования в сообществе Objective-C и продолжается по сей день.

Совсем недавно начали появляться менеджеры пакетов, такие как CocoaPods , который призван быть одновременно менеджером пакетов и хранилищем пакетов. Большую часть кода Objective-C с открытым исходным кодом, написанного за последние несколько лет, теперь можно установить с помощью CocoaPods.

Анализ языка

Реализации Objective-C используют тонкую систему времени выполнения , написанную на C [ нужна цитация ] , которая мало увеличивает размер приложения. Напротив, большинство объектно-ориентированных систем на момент их создания использовали большие среды выполнения виртуальных машин . Программы, написанные на Objective-C, как правило, не намного превышают размер их кода и библиотек (которые обычно не нужно включать в дистрибутив программного обеспечения), в отличие от систем Smalltalk, где используется большой объем памяти. используется только для того, чтобы открыть окно. Приложения Objective-C обычно больше, чем аналогичные приложения C или C++, поскольку динамическая типизация Objective-C не позволяет удалять или встраивать методы. Поскольку у программиста есть такая свобода делегировать, пересылать вызовы, создавать селекторы на лету и передавать их в систему времени выполнения, компилятор Objective-C не может считать безопасным удаление неиспользуемых методов или встраивание вызовов.

Аналогично, язык может быть реализован поверх существующих компиляторов C (в GCC сначала как препроцессор, затем как модуль), а не как новый компилятор. Это позволяет Objective-C использовать огромную существующую коллекцию кода C, библиотек, инструментов и т. д. Существующие библиотеки C могут быть заключены в оболочки Objective-C , чтобы обеспечить интерфейс в стиле OO. В этом аспекте она похожа на библиотеку GObject и язык Vala , которые широко используются при разработке приложений GTK .

Все эти практические изменения снизили барьер для входа , что, вероятно, было самой большой проблемой для широкого распространения Smalltalk в 1980-х годах.

Распространенной критикой является то, что Objective-C не имеет языковой поддержки пространств имен . Вместо этого программисты вынуждены добавлять префиксы к именам своих классов, которые традиционно короче имен пространств имен и, следовательно, более подвержены коллизиям. Начиная с 2007 года, все классы и функции macOS в среде программирования Cocoa имеют префикс «NS» (например, NSObject, NSButton), чтобы идентифицировать их как принадлежащие ядру macOS или iOS; «NS» происходит от названий классов, определенных во время разработки NeXTSTEP .

Поскольку Objective-C является строгим расширенным набором C, он не рассматривает примитивные типы C как первоклассные объекты .

В отличие от C++ , Objective-C не поддерживает перегрузку операторов . Также в отличие от C++, Objective-C позволяет объекту напрямую наследовать только от одного класса (запрещая множественное наследование ). Однако в большинстве случаев категории и протоколы могут использоваться как альтернативные способы достижения тех же результатов.

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

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

Первые версии Objective-C не поддерживали сборку мусора . В то время это решение было предметом споров, и многие люди считали длительные «мертвые времена» (когда Smalltalk выполнял сбор данных), чтобы сделать всю систему непригодной для использования. Некоторые сторонние реализации добавили эту функцию (в первую очередь GNUstep с использованием Boehm ), а Apple реализовала ее в Mac OS X v10.5 . [57] Однако в более поздних версиях macOS и iOS сбор мусора был отменен в пользу автоматического подсчета ссылок (ARC), представленного в 2011 году.

С помощью ARC компилятор автоматически вставляет вызовы сохранения и освобождения в код Objective-C на основе статического анализа кода . Автоматизация освобождает программиста от необходимости писать код управления памятью. ARC также добавляет слабые ссылки на язык Objective-C. [58]

Философские различия между Objective-C и C++

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

В дополнение к стилю процедурного программирования C, C++ напрямую поддерживает определенные формы объектно-ориентированного программирования , обобщенного программирования и метапрограммирования . C++ также поставляется с большой стандартной библиотекой , включающей несколько классов-контейнеров . Аналогичным образом, Objective-C добавляет в C объектно-ориентированное программирование , динамическую типизацию и отражение . Objective-C не предоставляет стандартной библиотеки как таковой , но в большинстве мест, где используется Objective-C, он используется с OpenStep -подобной библиотекой. такую ​​библиотеку, как OENSTEP , Cocoa или GNUstep , которая обеспечивает функциональность, аналогичную стандартной библиотеке C++.

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

Использование отражения является частью более широкого различия между динамическими (время выполнения) функциями и статическими (во время компиляции) функциями языка. Хотя Objective-C и C++ используют сочетание обеих функций, Objective-C явно ориентирован на решения во время выполнения, а C++ — на решения во время компиляции. Противоречие между динамическим и статическим программированием связано со многими классическими компромиссами в программировании: динамические функции добавляют гибкости, статические функции добавляют скорости и проверки типов.

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

Смотрите также

Рекомендации

  1. ^ «Версии времени выполнения и платформы». Разработчик.apple.com . Архивировано из оригинала 20 июля 2016 года . Проверено 24 декабря 2017 г.
  2. Латтнер, Крис (3 июня 2014 г.). «Домашняя страница Криса Лэттнера». Крис Лэттнер. Архивировано из оригинала 4 июня 2014 года . Проверено 3 июня 2014 г. Язык Swift — это продукт неустанных усилий команды языковых экспертов, гуру документации, ниндзя по оптимизации компиляторов и невероятно важной внутренней экспериментальной группы, которая предоставляла отзывы, помогающие совершенствовать и проверять идеи. Конечно, он также получил большую пользу от опыта, с трудом полученного многими другими языками в этой области, черпая идеи из Objective-C, Rust, Haskell, Ruby, Python, C#, CLU и многих других, чтобы их перечислять.
  3. ^ ab «Среды приложений». Яблоко. Июнь 2014. Архивировано из оригинала 16 февраля 2019 года . Проверено 13 февраля 2019 г.
  4. ^ Сингх, Амит (декабрь 2003 г.). «Краткая история Mac OS X». Внутреннее устройство Mac OS X. Архивировано из оригинала 14 мая 2012 года . Проверено 11 июня 2012 г.
  5. ^ Андерсон, Тим (ноябрь 2023 г.). «Похоже, что срок службы Apple Objective-C подходит к концу». Класс разработчиков . Проверено 23 декабря 2023 г.
  6. ^ Гарлинг, Калеб. «Язык программирования iPhone стал третьим по популярности в мире». Проводной . Архивировано из оригинала 9 сентября 2013 года . Проверено 20 мая 2013 г.
  7. ^ Венк, Ричард (2009). Какао: Том 5 справочника разработчиков Apple Developer Series. Джон Уайли и сыновья. ISBN 978-0-470-49589-6. Архивировано из оригинала 16 февраля 2017 года . Проверено 22 июля 2016 г.
  8. ^ Бьянкуцци, Федерико; Надзиратель, Шейн (2009). Мастера программирования. O'Reilly Media, Inc., стр. 242–246. ISBN 978-0-596-51517-1. Архивировано из оригинала 17 февраля 2017 года . Проверено 22 июля 2016 г.
  9. ^ Кокс, Брэд (1983). «Объектно-ориентированный прекомпилятор: программирование методов Smalltalk 80 на языке C». Уведомления ACM SIGPLAN . Нью-Йорк, штат Нью-Йорк: ACM . 18 (1). дои : 10.1145/948093.948095. S2CID  6975032 . Проверено 17 февраля 2011 г.
  10. ^ "Common Lisp и Readline" . Гитхаб . Архивировано из оригинала 6 сентября 2014 года . Проверено 15 сентября 2014 г. Проблема впервые возникла, когда NeXT предложила распространять модифицированный GCC на две части и позволять пользователю связывать их. Джобс спросил меня, законно ли это. В то время мне казалось, что так оно и есть, если следовать рассуждениям, подобным тем, которые вы используете; но поскольку результат был очень нежелателен для свободного программного обеспечения, я сказал, что мне придется обратиться к юристу. То, что сказал адвокат, меня удивило; он сказал, что судьи сочтут такие схемы «уловками» и будут к ним очень суровы. Он сказал, что судья спросит, действительно ли это одна программа, а не как она называется. Поэтому я вернулся к Джобсу и сказал, что, по нашему мнению, его план не разрешен GPL. Прямым результатом этого является то, что теперь у нас есть интерфейс Objective C. Они хотели распространять парсер Objective C как отдельный проприетарный пакет для связи с серверной частью GCC, но, поскольку я не был согласен с тем, что это разрешено, они сделали его бесплатным.
  11. ^ «GNUstep: Введение». Разработчики GNUstep/Проект GNU. Архивировано из оригинала 6 августа 2012 года . Проверено 29 июля 2012 г.
  12. ^ "Крестен Краб Торуп | LinkedIn" . www.linkedin.com . Архивировано из оригинала 15 июля 2014 года . Проверено 23 июня 2016 г.
  13. ^ «Написание кода Objective-C» . apple.com. 23 апреля 2013. Архивировано из оригинала 24 декабря 2013 года . Проверено 22 декабря 2013 г.
  14. ^ "Учебный лагерь Objective-C" . Архивировано из оригинала 11 февраля 2018 года . Проверено 11 февраля 2018 г. Objective-C — это строгий расширенный набор ANSI C.
  15. ^ «Изучение Objective-C». Архивировано из оригинала 4 сентября 2014 года . Проверено 4 сентября 2014 г. Objective-C — это объектно-ориентированный строгий расширенный набор C.
  16. Ли, Кейт (3 сентября 2013 г.). Про Цель-C. Апресс. ISBN 9781430250500. Архивировано из оригинала 14 мая 2018 года . Проверено 24 декабря 2017 г. - через Google Книги.
  17. ^ «Теги для заголовков Objective-C» . Архивировано из оригинала 1 апреля 2017 года . Проверено 11 февраля 2018 г. Objective-C — это надмножество C.
  18. ^ «AppScan Source 8.7 теперь доступен» . Архивировано из оригинала 3 февраля 2017 года . Проверено 11 февраля 2018 г. Язык программирования Objective-C является расширенной версией языка программирования C.
  19. Apple, Inc. (19 октября 2009 г.). «Разрешение динамического метода». Руководство по программированию во время выполнения Objective-C . Архивировано из оригинала 7 сентября 2010 года . Проверено 25 ноября 2014 г.
  20. Apple, Inc. (19 октября 2009 г.). «Как избежать ошибок при обмене сообщениями». Язык программирования Objective-C . Архивировано из оригинала 8 сентября 2010 года.
  21. ^ «objc_msgSend — среда выполнения Objective-C» . Документация разработчика Apple . Проверено 10 февраля 2020 г.
  22. ^ «Обмен сообщениями с помощью среды выполнения GNU Objective-C». Использование коллекции компиляторов GNU (GCC) . Проверено 10 февраля 2020 г.
  23. ^ «Категория». Разработчик Apple (основные компетенции Cocoa) .
  24. ^ Далримпл, Марк; Кнастер, Скотт (27 июня 2012 г.). Изучите Objective-C на Mac . Апресс. п. 9. ISBN 9781430241881. Расширение .m изначально обозначало «сообщения», когда Objective-C был впервые представлен, ссылаясь на центральную функцию Objective-C.
  25. ^ «Руководство по программированию во время выполнения Objective-C» . Apple Inc. Архивировано из оригинала 4 апреля 2014 года . Проверено 21 октября 2013 г.
  26. ^ "ACM SIGGRAPH 1983, выпуск 8 - Smalltalk" . Архивировано из оригинала 15 апреля 2009 года . Проверено 7 октября 2008 г.
  27. ^ «Методы расширения (Руководство по программированию на C#)» . Майкрософт. Октябрь 2010. Архивировано из оригинала 11 июля 2011 года . Проверено 10 июля 2011 г.
  28. ^ «Использование C++ с Objective-C». Справочная библиотека Mac OS X. Архивировано из оригинала 5 сентября 2010 года . Проверено 10 февраля 2010 г.
  29. ^ «Расширения языка Clang — документация Clang 3.5» . Clang.llvm.org. Архивировано из оригинала 24 февраля 2014 года . Проверено 16 апреля 2014 г.
  30. ^ «Objective-C 2.0: больше подсказок» . Списки.apple.com. 10 августа 2006. Архивировано из оригинала 18 июня 2009 года . Проверено 30 мая 2010 г.
  31. ^ "Re: Objective-C 2.0" . Списки.apple.com. Архивировано из оригинала 24 ноября 2010 года . Проверено 30 мая 2010 г.
  32. ^ ab «Серия выпусков GCC 4.6 — изменения, новые функции и исправления: Проект GNU: Фонд свободного программного обеспечения» . Gcc.gnu.org . Архивировано из оригинала 5 января 2018 года . Проверено 24 декабря 2017 г.
  33. ^ abcd «Часто задаваемые вопросы по ObjC2». GNUшаг . Проверено 6 января 2020 г.
  34. ^ «Браузер исходного кода: objc4, 756.2» . Apple с открытым исходным кодом . Проверено 6 января 2020 г.
  35. ^ Руководство по программированию сбора мусора: API сбора мусора. Архивировано 9 июня 2012 г. на Wayback Machine (веб-сайт разработчика Apple — найдите «__strong»)
  36. ^ «Руководство по программированию сборки мусора: Введение в сборку мусора» . Apple Inc., 3 октября 2011 г. Архивировано из оригинала 9 июня 2012 г. . Проверено 23 декабря 2011 г.
  37. ^ «Серия Leopard Technology для разработчиков: обзор Objective-C 2.0» . Apple Inc., 6 ноября 2007 г. Архивировано из оригинала 24 июля 2010 г. . Проверено 30 мая 2010 г.
  38. ^ «Переход на примечания к выпуску ARC» . Apple Inc., 17 июля 2012 г. Архивировано из оригинала 9 июня 2012 г. . Проверено 26 августа 2012 г.
  39. ^ Майк Эш. «Пятничные вопросы и ответы 27 сентября 2013 г.: ARM64 и вы». mikeash.com. Архивировано из оригинала 26 апреля 2014 года . Проверено 27 апреля 2014 г.
  40. ^ "Hamster Emporium: [объяснение объекта]: isa без указателя" . Sealiesoftware.com. 24 сентября 2013. Архивировано из оригинала 3 июня 2014 года . Проверено 27 апреля 2014 г.
  41. ^ Apple, Inc. (2009). «Быстрый пересчет». apple.com. Архивировано из оригинала 17 декабря 2009 года . Проверено 31 декабря 2009 г.
  42. ^ Фонд свободного программного обеспечения, Inc. (2011). «Серия выпусков GCC 4.6 – изменения, новые функции и исправления». Gcc.gnu.org . Архивировано из оригинала 2 декабря 2013 года . Проверено 27 ноября 2013 г.
  43. ^ «Темы программирования блоков - Библиотека разработчиков Mac» . Apple Inc., 8 марта 2011 г. Архивировано из оригинала 9 июня 2012 г. . Проверено 28 ноября 2012 г.
  44. ^ ab «Автоматический подсчет ссылок (ARC) Objective-C — документация Clang 11» . Документация по Clang . Проверено 20 февраля 2020 г. На данный момент имеет смысл обновлять этот документ по выпускам его единственной реализации (и основного проекта) — clang. «LLVM XY» относится к выпуску clang с открытым исходным кодом из проекта LLVM. «Apple XY» относится к предоставленной Apple версии компилятора Apple LLVM.
  45. ^ «Переход на ARC». Apple Inc. Архивировано из оригинала 7 сентября 2011 года . Проверено 8 октября 2012 г.
  46. ^ «Примечания к выпуску LLVM 3.0» . Releases.llvm.org .
  47. ^ ab «Программирование с использованием Objective-C: значения и коллекции». Apple Inc. Архивировано из оригинала 7 сентября 2011 года . Проверено 8 октября 2012 г.
  48. ^ «Примечания к выпуску Clang 3.1» . Releases.llvm.org .
  49. ^ «Литералы Objective-C — документация Clang 3.5» . Clang.llvm.org. Архивировано из оригинала 6 июня 2014 года . Проверено 16 апреля 2014 г.
  50. ^ Руководство разработчика Rhapsody , AP Professional, 1997, стр. 76–84.
  51. ^ «Портативный компилятор объектов» . Пользователи.pandora.be. 1 января 1970 года. Архивировано из оригинала 2 августа 2008 года . Проверено 30 мая 2010 г.
  52. ^ "Домашняя страница ООО Breadbox Computer Company" . Архивировано из оригинала 27 июля 2011 года . Проверено 8 декабря 2010 г.
  53. ^ "gcc/libobjc". Гитхаб . gcc-зеркало. 6 января 2020 г. Проверено 6 января 2020 г. среда выполнения была полностью переписана в gcc 2.4. В более ранней среде выполнения было несколько серьезных ошибок, и она была неполной.
  54. ^ «API среды выполнения GNU Objective-C» . Использование GCC . Проверено 6 января 2020 г.
  55. ^ «WinObjC на GitHub». Гитхаб . Архивировано из оригинала 2 декабря 2017 года . Проверено 13 февраля 2018 г.
  56. ^ "Установщик GNUStep" . Архивировано из оригинала 17 февраля 2018 года . Проверено 14 февраля 2018 г.
  57. Apple, Inc. (22 августа 2006 г.). «Mac OS X Leopard – Xcode 3.0». apple.com. Архивировано из оригинала 24 октября 2007 года . Проверено 22 августа 2006 г.
  58. ^ «Переход на примечания к выпуску ARC» . Библиотека разработчиков iOS . Разработчик.apple.com. Архивировано из оригинала 7 сентября 2011 года . Проверено 16 апреля 2014 г.

дальнейшее чтение

Внешние ссылки