stringtranslate.com

Objective-C

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

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

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

История

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

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

Кокс начал писать препроцессор для C, чтобы добавить некоторые возможности Smalltalk . Вскоре у него появилась рабочая реализация объектно-ориентированного расширения языка C , которое он назвал Object-Oriented Pre-Compiler (OOPC). [8] Лав был нанят 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 разработала библиотеки Application Kit (AppKit) и Foundation Kit , на которых были основаны пользовательский интерфейс NeXTSTEP и Interface Builder. Хотя рабочие станции NeXT не оказали большого влияния на рынок, эти инструменты получили широкое признание в отрасли. NeXT прекратила производство оборудования и сосредоточилась на программных инструментах, продавая NeXTSTEP (и OPENSTEP) как платформу для пользовательского программирования.

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

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

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

Разработка 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. [12] [13] [14] [15] [16] [17]

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

Сообщения

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

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

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

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

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

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

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

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

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

Интерфейс

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

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

Декларация интерфейса имеет вид:

@interface  classname  : superclassname  { // переменные экземпляра } + classMethod1 ; + ( return_type ) 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++ :

класс имя_класса : имя_суперкласса public { protected : // переменные экземпляра      public : // Функции класса (статические) static void * classMethod1 (); static return_type classMethod2 (); static 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 *, или указателем на класс, к которому принадлежит метод (instancetype). Тип возвращаемых данных по умолчанию — общий тип Objective-C id.

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

-  ( void ) setRangeStart: ( int ) начало конец: ( int ) конец ; - ( void ) importDocumentWithName: ( NSString * ) имя withSpecifiedPreferences :( Preferences * ) prefs beforePage :( int ) insertPage ;      

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

Выполнение

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

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

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

-  ( целое число ) метод: ( целое число ) i { return [ self square_root : i ]; }    
функция int ( int i ) { return square_root ( i ); }     

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

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

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

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

Инстанцирование

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

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

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

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

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

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

МойОбъект * foo = [ МойОбъект новый ];    

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

MyObject * foo = [ MyObject object ]; MyObject * bar = [ MyObject objectWithString : @"Wikipedia :)" ];        

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

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

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

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

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

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

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

Протоколы

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

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 -  ( void ) заблокировать ; -  ( void ) разблокировать ; @end

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

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

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

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

Objective-C, как и Smalltalk, может использовать динамическую типизацию : объекту можно отправить сообщение, которое не указано в его интерфейсе. Это может обеспечить большую гибкость, поскольку позволяет объекту «захватить» сообщение и отправить его другому объекту, который может соответствующим образом отреагировать на сообщение или аналогичным образом отправить сообщение другому объекту. Такое поведение известно как пересылка сообщений или делегирование (см. ниже). В качестве альтернативы можно использовать обработчик ошибок в случае, если сообщение не может быть переслано. Если объект не пересылает сообщение, не отвечает на него или не обрабатывает ошибку, то система сгенерирует исключение времени выполнения. [24] Если сообщения отправляются в 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::не нужно переопределять, так как этот метод просто выполняет действие на основе селектора и аргументов. Обратите внимание на SELтип, который является типом сообщений в Objective-C.

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

Пример

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

Форвардер.h
#импорт <objc/Object.h>@interface  Forwarder  : Object  { id receiveer ; // Объект, которому мы хотим переслать сообщение. }   // Методы доступа. -  ( id ) получатель ; -  ( id ) setRecipient: ( id ) _recipient ; @end
Экспедитор.м
#импорт "Forwarder.h"@implementation  Forwarder -  ( retval_t ) forward: ( SEL ) sel args: ( arglist_t ) args { /*  * Проверяет, действительно ли получатель отвечает на сообщение.  * Это может быть желательно или нет, например, если получатель  * в свою очередь не отвечает на сообщение, он может выполнить пересылку  * сам.  */ if ([ receiveer responsesToSelector : sel ]) { return [ receiveer performv : sel args : args ]; } else { return [ self error : "Recipient does not respond" ]; } }                  -  ( id ) setRecipient: ( id ) _recipient { [ автоматическое освобождение получателя ]; получатель = [ сохранение _recipient ]; возврат себя ; }         -  ( id ) получатель { return получатель ; } @end   
Получатель.h
#импорт <objc/Object.h>// Простой объект получателя. @interface  Получатель  : Объект -  ( id ) hello ; @end
Получатель.м
#импорт "Получатель.h"@implementation  Получатель-  ( id ) hello { printf ( "Получатель передает привет! \n " );   вернуть себя ; } @конец
основной.м
#импорт "Пересылка.h" #импорт "Получатель.h"int main ( void ) { Пересылающий * пересылающий = [ Новый пересылающий ]; Получатель * получатель = [ Новый получатель ];             [ forwarder setRecipient : receive ]; // Устанавливаем получателя. /*  * Наблюдаем, что пересылающий не отвечает на сообщение hello! Оно будет  * переслано. Все нераспознанные методы будут пересланы  * получателю  * (если получатель ответит на них, как написано в 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не отвечает на сообщения hello. В этом случае можно смело игнорировать предупреждение, поскольку была реализована пересылка. Запуск программы дает следующий вывод:

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

Категории

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

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

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

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

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

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

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

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

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

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

Примечания

Компиляция выполняется, например, следующим образом:

$ gcc  -x  objective-c  main.m Целое  число.m  Целое число+Арифметика.m  Целое число+Отображение.m  -lobjc

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

Позирование

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

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

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

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

Например,

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

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

#импорт

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

Компиляция Linux gcc

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

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

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

Варианты языка

Objective-C++

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

Objective-C 2.0

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

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

Сбор мусора

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

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

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

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

@interface  Person  : NSObject  { @public NSString * имя ; @private int возраст ; }    @property ( копия ) NSString * имя ; @property ( только чтение ) int возраст ;    -  ( id ) initWithAge: ( int ) age ; @end

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

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

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

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

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

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

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

int i ; int propertyCount = 0 ; objc_property_t * propertyList = class_copyPropertyList ([ aPerson class ], & propertyCount );         for ( i = 0 ; i < propertyCount ; i ++ ) { objc_property_t * thisProperty = propertyList + i ; 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 ]; Person * p ;     while (( p = [ enumerator nextObject ]) != nil ) { NSLog ( @"%@ is %i years old." , [ p name ], [ p age ]); }            
// Использование индексов for ( int i = 0 ; i < [ thePeople count ]; i ++ ) { Person * p = [ thePeople objectAtIndex : i ]; NSLog ( @"%@ is %i years old." , [ p name ], [ p age ]); }                    
// Используем быстрое перечисление for ( Person * p in thePeople ) { NSLog ( @"%@ is %i years old." , [ p name ], [ p age ]); }          

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

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

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

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

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

Блоки

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

#include <stdio.h> #include <Block.h> typedef int ( ^ IntBlock )();    IntBlock MakeCounter ( int start , int increment ) { __block int i = start ;           return Block_copy ( ^ { int ret = i ; i += increment ; 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 );  return 0 ; } /* Вывод:  Первый вызов: 5  Второй вызов: 7  Третий вызов: 9 */ 

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

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

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

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

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

Литералы

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

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

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

NSArray * myArray = [ NSArray arrayWithObjects : object1 , object2 , object3 , nil ]; NSDictionary * myDictionary1 = [ NSDictionary dictionaryWithObject : someObject forKey : @"key" ]; NSDictionary * myDictionary2 = [ NSDictionary dictionaryWithObjectsAndKeys : object1 , key1 , object2 , key2 , nil ]; NSNumber * myNumber = [ NSNumber numberWithInt : myInt ]; NSNumber * mySumNumber = [ NSNumber numberWithInt : ( 2 + 3 )]; NSNumber * myBoolNumber = [ NSNumber numberWithBool : YES ];                              

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

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

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

Подписка

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

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

id object1 = [ someArray objectAtIndex : 0 ]; id object2 = [ someDictionary objectForKey : @"key" ]; [ someMutableArray replaceObjectAtIndex : 0 withObject : object3 ]; [ someMutableDictionary setObject : object4 forKey : @"key" ];            

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

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

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

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

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

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

 объект = ( MyClass.alloc ) .init ; объект.labels ( param1 , param2 ) ;       

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

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

к

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

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

mulle-objc

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

Компилятор переносимых объектов

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

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

GEOS Objective-C

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

Лязг

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

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

GNU, GNUstep и WinObjC

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

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

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

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

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

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

Objective-C сегодня часто используется в тандеме с фиксированной библиотекой стандартных объектов (часто называемой «kit» или «framework»), такой как 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 . [56] Однако в более поздних версиях macOS и iOS сборка мусора была устарела в пользу автоматического подсчета ссылок (ARC), представленного в 2011 году.

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

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

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

В дополнение к стилю процедурного программирования C, C++ напрямую поддерживает определенные формы объектно-ориентированного программирования , обобщенного программирования и метапрограммирования . C++ также поставляется с большой стандартной библиотекой , которая включает несколько классов-контейнеров . Аналогично, Objective-C добавляет объектно-ориентированное программирование , динамическую типизацию и рефлексию в C. Objective-C не предоставляет стандартную библиотеку как таковую , но в большинстве мест, где используется Objective-C, он используется с библиотекой, похожей на OpenStep, такой как OPENSTEP , 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. ^ "Runtime Versions and Platforms". Developer.apple.com . Архивировано из оригинала 20 июля 2016 г. Получено 24 декабря 2017 г.
  2. ^ Lattner, Chris (3 июня 2014 г.). "Домашняя страница Криса Латтнера". Крис Латтнер. Архивировано из оригинала 4 июня 2014 г. Получено 3 июня 2014 г. Язык Swift является продуктом неустанных усилий команды экспертов по языку, гуру документации, ниндзя оптимизации компиляторов и невероятно важной внутренней группы по доводке, которая предоставляла обратную связь, чтобы помочь отточить и проверить идеи в бою. Конечно, он также значительно выиграл от опыта, полученного с трудом многими другими языками в этой области, черпая идеи из Objective-C, Rust, Haskell , Ruby , Python , C# , CLU и слишком многих других, чтобы перечислить их.
  3. ^ ab "App Frameworks". Apple. Июнь 2014. Архивировано из оригинала 16 февраля 2019 г. Получено 13 февраля 2019 г.
  4. ^ Сингх, Амит (декабрь 2003 г.). "Краткая история Mac OS X". Внутреннее устройство Mac OS X. Архивировано из оригинала 14 мая 2012 г. Получено 11 июня 2012 г.
  5. ^ Гарлинг, Кейлеб. «Язык программирования iPhone теперь третий по популярности в мире». Wired . Архивировано из оригинала 9 сентября 2013 г. Получено 20 мая 2013 г.
  6. ^ Вентк, Ричард (2009). Какао: Том 5 из серии «Справочник разработчика Apple Developer». John Wiley and Sons. ISBN 978-0-470-49589-6. Архивировано из оригинала 16 февраля 2017 г. . Получено 22 июля 2016 г. .
  7. ^ Бьянкуцци, Федерико; Надзиратель, Шейн (2009). Мастера программирования. O'Reilly Media, Inc., стр. 242–246. ISBN 978-0-596-51517-1. Архивировано из оригинала 17 февраля 2017 г. . Получено 22 июля 2016 г. .
  8. ^ Кокс, Брэд (1983). «Объектно-ориентированный прекомпилятор: программирование методов Smalltalk-80 на языке C». ACM SIGPLAN Notices . 18 (1). Нью-Йорк, штат Нью-Йорк: ACM . doi :10.1145/948093.948095. S2CID  6975032. Получено 17 февраля 2011 г.
  9. ^ "Common Lisp and Readline". GitHub . Архивировано из оригинала 6 сентября 2014 г. Получено 15 сентября 2014 г. Впервые проблема возникла, когда NeXT предложила распространять модифицированный GCC двумя частями и позволить пользователю связывать их. Джобс спросил меня, законно ли это. В то время мне казалось, что это так, следуя рассуждениям вроде того, что вы используете; но поскольку результат был очень нежелательным для свободного программного обеспечения, я сказал, что мне придется спросить юриста. То, что сказал юрист, удивило меня; он сказал, что судьи сочтут такие схемы "уловками" и будут очень суровы по отношению к ним. Он сказал, что судья спросит, является ли это "действительно" одной программой, а не как она маркирована. Поэтому я вернулся к Джобсу и сказал, что мы считаем, что его план не разрешен GPL. Прямым результатом этого является то, что теперь у нас есть фронтенд Objective-C. Они хотели распространять парсер Objective C как отдельный фирменный пакет для связи с бэкэндом GCC, но поскольку я не согласился с тем, что это разрешено, они сделали его бесплатным.
  10. ^ "GNUstep: Introduction". Разработчики GNUstep/Проект GNU. Архивировано из оригинала 6 августа 2012 г. Получено 29 июля 2012 г.
  11. ^ "Kresten Krab Thorup | LinkedIn". www.linkedin.com . Архивировано из оригинала 15 июля 2014 г. Получено 23 июня 2016 г.
  12. ^ "Write Objective-C Code". apple.com. 23 апреля 2013 г. Архивировано из оригинала 24 декабря 2013 г. Получено 22 декабря 2013 г.
  13. ^ "Objective-C Boot Camp". Архивировано из оригинала 11 февраля 2018 г. Получено 11 февраля 2018 г. Objective -C является строгим надмножеством ANSI C
  14. ^ "Examining Objective-C". Архивировано из оригинала 4 сентября 2014 г. Получено 4 сентября 2014 г. Objective -C — это объектно-ориентированное строгое надмножество языка C
  15. Ли, Кейт (3 сентября 2013 г.). Про Цель-C. Апресс. ISBN 9781430250500. Архивировано из оригинала 14 мая 2018 г. . Получено 24 декабря 2017 г. – через Google Books.
  16. ^ "Теги для заголовков Objective-C". Архивировано из оригинала 1 апреля 2017 г. Получено 11 февраля 2018 г. Objective -C — это надмножество C
  17. ^ "AppScan Source 8.7 теперь доступен". Архивировано из оригинала 3 февраля 2017 г. Получено 11 февраля 2018 г. Язык программирования Objective-C является надмножеством языка программирования C
  18. ^ Apple, Inc. (19 октября 2009 г.). "Dynamic Method Resolution". Objective-C Runtime Programming Guide . Архивировано из оригинала 7 сентября 2010 г. Получено 25 ноября 2014 г.
  19. ^ Apple, Inc. (19 октября 2009 г.). «Избегание ошибок обмена сообщениями». Язык программирования Objective-C . Архивировано из оригинала 8 сентября 2010 г.
  20. ^ "objc_msgSend - Objective-C Runtime". Документация разработчика Apple . Получено 10 февраля 2020 г.
  21. ^ "Обмен сообщениями с GNU Objective-C runtime". Использование GNU Compiler Collection (GCC) . Получено 10 февраля 2020 г.
  22. ^ "Категория". Разработчик Apple (Cocoa Core Competencies) .
  23. ^ Далримпл, Марк; Кнастер, Скотт (27 июня 2012 г.). Изучите Objective-C на Mac . Apress. стр. 9. ISBN 9781430241881. Расширение .m изначально означало «сообщения», когда Objective-C был впервые представлен, ссылаясь на центральную функцию Objective-C.
  24. ^ "Objective-C Runtime Programming Guide". Apple Inc. Архивировано из оригинала 4 апреля 2014 г. Получено 21 октября 2013 г.
  25. ^ "ACM SIGGRAPH 1983 Issue 8 - Smalltalk". Архивировано из оригинала 15 апреля 2009 года . Получено 7 октября 2008 года .
  26. ^ "Методы расширения (Руководство по программированию на C#)". Microsoft. Октябрь 2010. Архивировано из оригинала 11 июля 2011 г. Получено 10 июля 2011 г.
  27. ^ "Использование C++ с Objective-C". Справочная библиотека Mac OS X. Архивировано из оригинала 5 сентября 2010 г. Получено 10 февраля 2010 г.
  28. ^ "Clang Language Extensions — Clang 3.5 documentation". Clang.llvm.org. Архивировано из оригинала 24 февраля 2014 г. Получено 16 апреля 2014 г.
  29. ^ "Objective-C 2.0: more clues". Lists.apple.com. 10 августа 2006 г. Архивировано из оригинала 18 июня 2009 г. Получено 30 мая 2010 г.
  30. ^ "Re: Objective-C 2.0". Lists.apple.com. Архивировано из оригинала 24 ноября 2010 г. Получено 30 мая 2010 г.
  31. ^ ab "GCC 4.6 Release Series — Changes, New Features, and Fixes : GNU Project : Free Software Foundation". Gcc.gnu.org . Архивировано из оригинала 5 января 2018 г. . Получено 24 декабря 2017 г. .
  32. ^ abcd "ObjC2 FAQ". GNUstep . Получено 6 января 2020 г. .
  33. ^ "Исходный браузер: objc4, 756.2". Apple Open Source . Получено 6 января 2020 г.
  34. ^ Руководство по программированию сборки мусора: API сборки мусора. Архивировано 9 июня 2012 г. на Wayback Machine (сайт разработчиков Apple — найдите «__strong»).
  35. ^ "Garbage Collection Programming Guide: Introduction to Garbage Collection". Apple Inc. 3 октября 2011 г. Архивировано из оригинала 9 июня 2012 г. Получено 23 декабря 2011 г.
  36. ^ "Leopard Technology Series for Developers: Objective-C 2.0 Overview". Apple Inc. 6 ноября 2007 г. Архивировано из оригинала 24 июля 2010 г. Получено 30 мая 2010 г.
  37. ^ «Transitioning to ARC Release Notes». Apple Inc. 17 июля 2012 г. Архивировано из оригинала 9 июня 2012 г. Получено 26 августа 2012 г.
  38. ^ Майк Эш. "Пятничные вопросы и ответы 2013-09-27: ARM64 и вы". mikeash.com. Архивировано из оригинала 26 апреля 2014 г. Получено 27 апреля 2014 г.
  39. ^ "Hamster Emporium: [objc Explain]: Неуказательный isa". Sealiesoftware.com. 24 сентября 2013 г. Архивировано из оригинала 3 июня 2014 г. Получено 27 апреля 2014 г.
  40. ^ Apple, Inc. (2009). "Быстрое перечисление". apple.com. Архивировано из оригинала 17 декабря 2009 года . Получено 31 декабря 2009 года .
  41. ^ Free Software Foundation, Inc. (2011). "GCC 4.6 Release Series – Changes, New Features, and Fixes". Gcc.gnu.org . Архивировано из оригинала 2 декабря 2013 г. . Получено 27 ноября 2013 г. .
  42. ^ "Blocks Programming Topics – Mac Developer Library". Apple Inc. 8 марта 2011 г. Архивировано из оригинала 9 июня 2012 г. Получено 28 ноября 2012 г.
  43. ^ ab "Objective-C Automatic Reference Counting (ARC) — документация Clang 11". Документация Clang . Получено 20 февраля 2020 г. На данный момент разумно версионировать этот документ по выпускам его единственной реализации (и ее основного проекта), clang. "LLVM XY" относится к выпуску clang с открытым исходным кодом из проекта LLVM. "Apple XY" относится к предоставленному Apple выпуску компилятора Apple LLVM.
  44. ^ "Переход на ARC". Apple Inc. Архивировано из оригинала 7 сентября 2011 г. Получено 8 октября 2012 г.
  45. ^ "Заметки о выпуске LLVM 3.0". releases.llvm.org .
  46. ^ ab "Программирование на Objective-C: Значения и коллекции". Apple Inc. Архивировано из оригинала 7 сентября 2011 г. Получено 8 октября 2012 г.
  47. ^ "Заметки о выпуске Clang 3.1". releases.llvm.org .
  48. ^ "Objective-C Literals — Clang 3.5 documentation". Clang.llvm.org. Архивировано из оригинала 6 июня 2014 г. Получено 16 апреля 2014 г.
  49. ^ Руководство разработчика Rhapsody , AP Professional, 1997, стр. 76–84
  50. ^ "Portable Object Compiler". Users.pandora.be. 1 января 1970 г. Архивировано из оригинала 2 августа 2008 г. Получено 30 мая 2010 г.
  51. ^ "Breadbox Computer Company LLC homepage". Архивировано из оригинала 27 июля 2011 г. Получено 8 декабря 2010 г.
  52. ^ "gcc/libobjc". GitHub . gcc-mirror. 6 января 2020 г. Получено 6 января 2020 г. среда выполнения была полностью переписана в gcc 2.4. Более ранняя среда выполнения имела несколько серьезных ошибок и была довольно неполной.
  53. ^ "GNU Objective-C runtime API". Использование GCC . Получено 6 января 2020 г.
  54. ^ "WinObjC на GitHub". GitHub . Архивировано из оригинала 2 декабря 2017 г. Получено 13 февраля 2018 г.
  55. ^ "GNUStep Installer". Архивировано из оригинала 17 февраля 2018 г. Получено 14 февраля 2018 г.
  56. Apple, Inc. (22 августа 2006 г.). «Mac OS X Leopard – Xcode 3.0». apple.com. Архивировано из оригинала 24 октября 2007 г. Получено 22 августа 2006 г.
  57. ^ "Transitioning to ARC Release Notes". Библиотека разработчиков iOS . Developer.apple.com. Архивировано из оригинала 7 сентября 2011 г. Получено 16 апреля 2014 г.

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

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