- Programming with Objective-C
- About Objective-C
- At a Glance
- An App Is Built from a Network of Objects
- Categories Extend Existing Classes
- Protocols Define Messaging Contracts
- Values and Collections Are Often Represented as Objective-C Objects
- Blocks Simplify Common Tasks
- Error Objects Are Used for Runtime Problems
- Objective-C Code Follows Established Conventions
- Prerequisites
- See Also
- Objective-C с нуля
- Банальная теория возникновения ООП
- Чуть-чуть истории
- Особенности Objective-C
- Обмен сообщениями
- Как работает передача сообщений
- Объявление метода
- Объявление класса
- Создание объектов
- Время жизни объекта
- Методы доступа
- Самовыгружаемый пул в нитях программы
- Определение класса
- Категории и расширения
- Протоколы
- Исключения
- Свойства
Programming with Objective-C
About Objective-C
Objective-C is the primary programming language you use when writing software for OS X and iOS. It’s a superset of the C programming language and provides object-oriented capabilities and a dynamic runtime. Objective-C inherits the syntax, primitive types, and flow control statements of C and adds syntax for defining classes and methods. It also adds language-level support for object graph management and object literals while providing dynamic typing and binding, deferring many responsibilities until runtime.
At a Glance
This document introduces the Objective-C language and offers extensive examples of its use. You’ll learn how to create your own classes describing custom objects and see how to work with some of the framework classes provided by Cocoa and Cocoa Touch. Although the framework classes are separate from the language, their use is tightly wound into coding with Objective-C and many language-level features rely on behavior offered by these classes.
An App Is Built from a Network of Objects
When building apps for OS X or iOS, you’ll spend most of your time working with objects. Those objects are instances of Objective-C classes, some of which are provided for you by Cocoa or Cocoa Touch and some of which you’ll write yourself.
If you’re writing your own class, start by providing a description of the class that details the intended public interface to instances of the class. This interface includes the public properties to encapsulate relevant data, along with a list of methods. Method declarations indicate the messages that an object can receive, and include information about the parameters required whenever the method is called. You’ll also provide a class implementation, which includes the executable code for each method declared in the interface.
Categories Extend Existing Classes
Rather than creating an entirely new class to provide minor additional capabilities over an existing class, it’s possible to define a category to add custom behavior to an existing class. You can use a category to add methods to any class, including classes for which you don’t have the original implementation source code, such as framework classes like NSString .
If you do have the original source code for a class, you can use a class extension to add new properties, or modify the attributes of existing properties. Class extensions are commonly used to hide private behavior for use either within a single source code file, or within the private implementation of a custom framework.
Protocols Define Messaging Contracts
The majority of work in an Objective-C app occurs as a result of objects sending messages to each other. Often, these messages are defined by the methods declared explicitly in a class interface. Sometimes, however, it is useful to be able to define a set of related methods that aren’t tied directly to a specific class.
Objective-C uses protocols to define a group of related methods, such as the methods an object might call on its delegate , which are either optional or required. Any class can indicate that it adopts a protocol, which means that it must also provide implementations for all of the required methods in the protocol.
Relevant Chapters: Working with Protocols
Values and Collections Are Often Represented as Objective-C Objects
It’s common in Objective-C to use Cocoa or Cocoa Touch classes to represent values. The NSString class is used for strings of characters, the NSNumber class for different types of numbers such as integer or floating point, and the NSValue class for other values such as C structures. You can also use any of the primitive types defined by the C language, such as int , float or char .
Collections are usually represented as instances of one of the collection classes, such as NSArray , NSSet , or NSDictionary , which are each used to collect other Objective-C objects.
Relevant Chapters: Values and Collections
Blocks Simplify Common Tasks
Blocks are a language feature introduced to C, Objective-C and C++ to represent a unit of work; they encapsulate a block of code along with captured state, which makes them similar to closures in other programming languages. Blocks are often used to simplify common tasks such as collection enumeration, sorting and testing. They also make it easy to schedule tasks for concurrent or asynchronous execution using technologies like Grand Central Dispatch (GCD).
Relevant Chapters: Working with Blocks
Error Objects Are Used for Runtime Problems
Although Objective-C includes syntax for exception handling, Cocoa and Cocoa Touch use exceptions only for programming errors (such as out of bounds array access), which should be fixed before an app is shipped.
All other errors—including runtime problems such as running out of disk space or not being able to access a web service—are represented by instances of the NSError class. Your app should plan for errors and decide how best to handle them in order to present the best possible user experience when something goes wrong.
Relevant Chapters: Dealing with Errors
Objective-C Code Follows Established Conventions
When writing Objective-C code, you should keep in mind a number of established coding conventions. Method names, for example, start with a lowercase letter and use camel case for multiple words; for example, doSomething or doSomethingElse . It’s not just the capitalization that’s important, though; you should also make sure that your code is as readable as possible, which means that method names should be expressive, but not too verbose.
In addition, there are a few conventions that are required if you wish to take advantage of language or framework features. Property accessor methods, for example, must follow strict naming conventions in order to work with technologies like Key-Value Coding (KVC) or Key-Value Observing (KVO).
Relevant Chapters: Conventions
Prerequisites
If you are new to OS X or iOS development, you should read through Start Developing iOS Apps Today (Retired) or Start Developing Mac Apps Today before reading this document, to get a general overview of the application development process for iOS and OS X. Additionally, you should become familiar with Xcode before trying to follow the exercises at the end of most chapters in this document. Xcode is the IDE used to build apps for iOS and OS X; you’ll use it to write your code, design your app’s user interface, test your application, and debug any problems.
Although it’s preferable to have some familiarity with C or one of the C-based languages such as Java or C#, this document does include inline examples of basic C language features such as flow control statements. If you have knowledge of another higher-level programming language, such as Ruby or Python, you should be able to follow the content.
Reasonable coverage is given to general object-oriented programming principles, particularly as they apply in the context of Objective-C, but it is assumed that you have at least a minimal familiarity with basic object-oriented concepts. If you’re not familiar with these concepts, you should read the relevant chapters in Concepts in Objective-C Programming.
See Also
The content in this document applies to Xcode 4.4 or later and assumes you are targeting either OS X v10.7 or later, or iOS 5 or later. For more information about Xcode, see Xcode Overview. For information on language feature availability, see Objective-C Feature Availability Index.
Objective-C apps use reference counting to determine the lifetime of objects. For the most part, the Automatic Reference Counting (ARC) feature of the compiler takes care of this for you. If you are unable to take advantage of ARC, or need to convert or maintain legacy code that manages an object’s memory manually, you should read Advanced Memory Management Programming Guide.
In addition to the compiler, the Objective-C language uses a runtime system to enable its dynamic and object-oriented features. Although you don’t usually need to worry about how Objective-C “works,” it’s possible to interact directly with this runtime system, as described by Objective-C Runtime Programming Guide and Objective-C Runtime Reference.
Copyright © 2014 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2014-09-17
Источник
Objective-C с нуля
Банальная теория возникновения ООП
Проблема повторного использования написанного кода и его переносимость постоянно заставляет программистов искать все новые пути его упорядочивания, структуризации и абстрагирования. Для решения этих проблем создаются новые парадигмы программирования, шаблоны проектирования, новые языки, компиляторы и стандартные библиотеки к ним, программные платформы и фреймворки. Так образовались парадигма подпрограмм (процедур), реализуемая при помощи процессорных команд CALL\RET и стека (по сути, перенос потока выполнения по адресу произвольной, а не следующей за текущей команды, с последующим возвратом). Затем, парадигма модулей (каждый файл – отдельная единица трансляции), породившая двухэтапную трансляцию: компиляция модулей, а затем их компоновка (статическая или динамическая) в исполняемый модуль.
В следствии увеличения объема кода в проектах и сложностей его поддержки, с 1960х начинает образовываться новая, объектно-ориентированная парадигма программирования, разбившая программы на еще более мелкие составляющие – типы данных. Ее суть заключается во взаимодействии сущностей (объектов) посредством посылки друг другу сообщений. Каждый объект является переменной определенного программистом типа данных (так называемого класса). Определение такого специального пользовательского типа данных (класса) заключается в двух вещах: определении набора данных (инвариантов, членов) и набора подпрограмм (методов), которые будут их обслуживать.
Класс обычно оформляется как определенный программистом тип, основанный на встроенных (языковых) типах данных и\или других классах. Для языка С, не поддерживающего объектно-ориентированную парадигму, это может быть структура (struct). А набор подпрограмм реализуется как обычные функции, обязательно принимающие как минимум один параметр — указатель на набор данных, подлежащих обработке.
Основным преимуществом объектно-ориентированного подхода стала возможность создавать новые классы на основе уже написанных (добавлять инварианты и методы, переопределять методы, использовать определенные в базовом классе методы как свои), названное наследованием.
Набор методов представляет собой интерфейс для взаимодействия с инвариантами. Невозможность непосредственной модификации данных класса (без задействования его интерфейса) отражает принцип инкапсуляции. На рисунке показан класс и его объекты. Имеется инвариант x типа float и к нему интерфейс (метод) doubleX, возвращающий значение инварианта.
Бывает, что необходимо послать сообщение объекту, который на него определенно отвечает (т.е. вызвать для объекта класса такой метод, который он реализовал), но, по ситуации, конкретный класс этого объекта неизвестен. Например, каждому элементу списка указателей на объекты класса Auto нужно послать сообщение Move, а известно что в списке находятся указатели на объекты не только класса Auto, но также и указатели на производные (наследованные) классы Ford и Subaru. Это возможно сделать только благодаря принципу полиморфизма, заключающегося в том, что при посылке определенного сообщения объекту из некой иерархии классов, в которой все объекты способны принять такое сообщение, этот объект реагирует на него соответственно своему, а не базовому для данной иерархии классу.
Первым языком с поддержкой объектно-ориентированного подхода стал Simula67. Затем появился Smalltalk. А в 80х начал оформляться С++ — основной язык современного системного программирования. Его расширение и усовершенствование в 90х породило ряд парадигм и шаблонов проектирования, и оказало необратимое влияние на современное видение объектно-ориентированного подхода, в том числе, и на язык Objective-C.
Чуть-чуть истории
Objective-C возник в 80-x как модификация С в сторону Smalltalk. Причем модификация эта состояла в добавлении новых синтаксических конструкций и специальном препроцессоре для них (который, проходя по коду преобразовывал их в обычные вызовы функций С), а также библиотеке времени выполнения (эти вызовы обрабатывающей). Таким образом, изначально Objective-C воспринимался как надстройка над C. В каком-то смысле это так и до сих пор: можно написать программу на чистом С, а после добавить к ней немного конструкций из Objective-C (при необходимости), или же наоборот, свободно пользоваться С в программах на Objective-C. Кроме того, все это касается и программ на С++. В 1988 NeXT (а в последствии Apple) лицензировала Objective-C и написала для него компилятор и стандартную библиотеку (по сути SDK). В 1992 к усовершенствованию языка и компилятора подключились разработчики проекта GNU в рамках проекта OpenStep. С тех пор GCC поддерживает Objective-C. После покупки NeXT, Apple взяля их SDK (компилятор, библиотеки, IDE) за основу для своих дальнейших разработок. IDE для кода назвали Xcode, а для GUI – Interface Builder. Фреймворк Cocoa для GUI разработок (и не только) на сегодня является наиболее значимой средой разработки программ на Objective-C.
Особенности Objective-C
Обмен сообщениями
Чтобы заставить объект выполнить какой-нибудь метод нужно послать ему сообщение, именуемое так же, как и требуемый метод. Такое сообщение называется селектор метода. Синтаксис посылки таков:
В сообщении можно передавать параметры для вызываемого метода:
Перед каждым параметром необходимо ставить двоеточие. Сколько двоеточий – столько и параметров. Имя метода может продолжаться после каждого такого двоеточия-параметра:
Методы с неограниченным количством аргументов вызываюся следующим синтаксисом:
Посылка сообщения, как и любая функция C, возвращает определенное (может void) значение:
При посылке сообщения nil оно просто пропадает. При посылке сообщения объекту, который принадлежит классу, не реализовавшему заказанный метод, возникает исключение, которое, будучи не перехваченным, приводит всю программу к незапланированному завершению. Для проверки, отвечает ли данный объект на кокое-либо сообщение можно использовать следующий шаблон кода:
Как работает передача сообщений
Посылка сообщения транслируется в С-функцию с прототипом:
Тип SEL, по сути, определен как char const *, но лучше воспринимать его как int, поскольку во время выполнения все селекторы индексируются целыми значениями согласно глобальной таблице селекторов.
Пользуясь инвариантом isa объекта receiver (при использовании фреймворка Foundation, базового для Cocoa, все классы должны наследовать класс NSObject, поэтому наличие isa неизбежно), эта функция просматривает локальный список селекторов класса с целью определить, отвечает ли объект данного класса на сообщение method. Если такой селектор находится, то управление передается соответствующему методу класса, которому передается id объекта (указатель на его инварианты) и указанные после селектора параметры функции objc_msgSend(). Значение, возвращенное методом, отдается как результат посылки сообщения. Если у объекта-приемника данный селектор отсутствует, функции objc_msgSend() просматривает список селекторов его базового класса.
При такой схеме вызов, например:
Так как в глобальной таблице селекторов 12 соответствует строке “addObject:”. Далее функция objc_msgSend() выполняет поиск по списку селекторов объекта receiver и, найдя его (пусть это объект класса NSArray, который реализовал метод с селектором 12), производит вызов типа:
Объявление метода
Интересно отметить, что прототип метода addObject из предыдущего раздела в объявлении класса выглядел так:
То есть принимал всего один параметр. Но, исходя из принципа объектно-ориентированной парадигмы, что методы – это подпрограммы, обрабатывающие определенные наборы данных, методу необходимо передавать адресс данных, подлежащих обработке. Поэтому такой параметр передается во всякий метод класса неявно. Компилятору об этом дополнительном параметре дает понять минус («-«), стоящий первым в прототипе метода. Такой метод (с минусом впереди) называется методом объекта (или экземпляра), т.к. может быть вызван только для объекта какого-нибудь класса. В теле метода этот указатель на экземпляр данных (или адрес объекта, которому послали сообщение) доступен посредством зарезервированного слова self (аналог this в С++), а указатель на экземпляр базового класса – через зарезервированное слово super. Кроме того, в метод объекта также передается неявный параметр _cmd – селектор этого метода из глобальной таблицы селекторов. С точки зрения программиста С++ все методы объектов в Objective-C как-будто объявлены с ключевым словом virtual, и всегда следуют динамическому полиморфизму.
Если в начале прототипа метода поставить знак плюс (“+”), то такой метод будет считаться методом класса, и, естественно, не будет принимать неявный параметр self (это аналогично объявлению static-метода в С++). А без инварианта isa объекта, на который указывает self, указатель super работать, конечно, тоже не будет.
Таким образом, прототип любого метода объявляется так:
Если метод возвращает некий объект (тип id) или класс (тип Class), можно воспользоваться вложенным синтаксисом вызова:
Здесь объекту класса UILabel из фреймворка UIKit устанавливается значение инварианта text равное строке @”Hello world”. Эта строка, в свою очередь, образована конкатенацией строк @”Hello” и @” world”. Первая является результатом посылке сообщения stringWithString классу NSString с параметром-константой @”Hello”. Такой вызов возвращает объект класса NSString, инициализированный строкой-параметром. Затем этому объекту посылается сообщение stringByAppendingString с параметром @” world”. Результат посылки этого сообщения и есть объект класса NSString, содержащий конкатенацию значения объекта-приемника и строкового аргумента. Этот объект и попадает как параметр в сообщение setText: объекта myLabel.
Объявление класса
Объявим простой класс комплексного числа в файле Complex.h:
Как видим, все объявление заключено в ключевые слова interface и end. Первым делом объявляются инварианты (в фигурных скобках). Вне фигурных скобок объявляются методы. Метод description отсутствует в объявлении класса не случайно. Дело в том, что он, как и метод dealloc и init, присутствует в определении класса. При посылке объекту класса Complex сообщения description будет рассмотрен его локальный список селекторов, куда, после компиляции, попадут селекторы всех методов, реализованных классом этого объекта, даже не объявленные в интерфейсной части. То есть init, description и dealloc будут вызывать абсолютно корректно.
Создание объектов
В связи с тем, что все объекты распределяютя в динамической памяти, cоздание объекта приходится проводить в два этапа: 1) выделении памяти (сообщение alloc) и 2) инициализация инвариантов (конструкторы класса).
После создания объекта им можно смело пользоваться:
Некоторые классы обладают методом для быстрого (в один этап) создания собственных экземпляров. Такие методы являются методами класса, возвращают указатель на объект своего класса и их имя обычно начинается с названия самого класса. Например метод:
Возвращает уже готовую строку, инициализированную соответствующей сторокой с завершающим нулем, без вызовов alloc и init:
Время жизни объекта
Как только указатель на объект выходит за свою область видимости, память, выделенная под него, безвозвратно теряется (если, конечно, это был последний указатель на тот объект) и происходит утечка. Дабы избежать таких нежелательных последствий в Objective-C поддерживается парадигма подсчета ссылок на ресурсы. Таким образом, у каждого объекта есть целочисленный счетчик, который показывает количество ссылающихся на него указателей. По достижению этим счетчиком нуля, память, выделенная для данного объекта, возвращается системе. После вызова метода класса alloc, этот счетчик равен единице. Чтобы увеличить его значение необходимо послать объекту сообщение retain, а чтобы уменьшить – release. Все эти методу реализует NSObject, который любой наш класс непременно наследует. Интересно отметить, что значение счетчика для статических объектов класса NSString (например @”I am a string”) равно -1, то есть максимально возможное. Вот пример работы со счетчиком:
Реализация init очень важна. Это конструктор класса. Конструкторы отличаются тем, что возвращаеют id и их названия всегда начинается со слова init, а конструктор по умолчанию – это и есть просто init. Схема любого конструктора примерно следующая:
Вот типичный специализированный (не по умолчанию) конструктор для класса с двумя членами типа некоторого класса и одним целочисленным инвариантом:
Реализация release и retain для NSObject идеологически примерно следующая, и ее не нужно переопределять в производных классах, в силу отсутствия доступа к инварианту счетчика ссылок:
То есть самому объекту посылается сообщение dealloc, в реализации метода которого он может, по необходимости, уменьшить счетчики своих инвариантов и передать аналогичное сообщение объекту базового класса, чтобы он сделал то же самое. Очевидно, реализация метода dealloc для NSObject освободит память, выделенную объекту. Обычно dealloc для какого-нибудь класса выглядит так:
Методы доступа
Правильная работа с подсчетом ссылок очень важна при возврате адреса объекта из метода или инициализации инварианта формальным параметром. Обычно такими вещами занимаются так называемые методы доступа, возвращающие и устанавливающие инварианты объектов. Принято именовать метод, возвращающий значение инварианта, так же как и инвариант, а имя метода, устанавливающего его значение, начинать со слова set:
Так как инвариант _re относится ко встроенному типу, никаких сложностей с изменением его значения не возникает. Но если инвариант – объект некоторого класса – то простым присваиванием не обойтись, ведь надо учитывать счетчики ссылок. Для решения этой проблемы применяются следующие три метода:
Вариант №3 не очень удачный потому, что засоряет текущий самовыгружаемый пул, а обычно это не очень желательно (см. следующий раздел).
Метод доступа для чтения значения инварианта всегда очень прост:
Самовыгружаемый пул в нитях программы
Теперь попробуем вернуть из метода созданный внутри него объект:
Строка формата соответствует стандарту языка С. Но если в ней необходимо указать тип id, то используется спецификатор формата %@. Каким образом метод, разбирающий формат, понимает какие символы подставить вместь id? Он просто подставит то, что вернет метод описания description данного объекта. Этот метод изначально объявлен для класса NSObject. NSString переопределил его на вывод своего строкового содержания. Переопределив его, любой объект может представлять свое строковое содержание. Например, так это может сделать класс комплексного числа с двумя инвариантами типа double:
После выполнения метода sayHelloToName:withSurname: определенно произойдет утечка памяти, так как вызывающий код скорей всего не догадывается, что возвращенному объекту нужно после обработки послать сообщение release. Даже если он догадается это сделать, возможно, что возвращался указатель на инвариант объекта, а значит его уничтожение чревато серьезными последствиями. Хотелось бы иметь механизм самоосвобождения объектов когда либо в будующем, чтобы пользовательский код вообще не думал об их освобождении. Решается эта проблема с помощью объекта класса NSAutoreleasePool – самовыгружаемого пула объектов.
После создания объекта такого класса всем объектам, созданным после него, можно послать сообщения autorelease. При этом данный объект помещается в текущий (последний созданный) самовыгружаемый пул. Когда некий пул получит сообщение release, то он отошлет такое же сообщение и всем своим объектам, уменьшая их счетчик ссылок (по сути, уничтожая). Таким образом. Объект, помещенный в самовыгружаемый пул, продолжает жить и занимать память во все время жизни пула. Это удобно для небольших временных объектов, но может с течением времени занять значительную часть памяти. Потому рекомендуется циклы, способные порождать большое количество временных объектов, которые отправляются в самовыгружаемый пул, обрамлять локальными (вложенными) пулами.
Любая нить в программе, использующей Cocoa, должна создавать объект класса NSAutoreleasePool в самом начале (прежде создания других объектов), и в самом конце его уничтожать (после уничтожения всех других объектов). Функция main(), являющаяся главной нитью любой программы на Objective-C, при использовании фреймворка Cocoa должна всегда выглядеть вот так:
А корректный метод sayHelloToName:withSurname: теперь будет выглядеть вот так:
К слову, метод drain самовыгружаемого пула аналогичен release с той лишь разницей, что, кроме освобождения себя самомго и всех содержащихся объектов, еще дает подсказку сборщику мусора вступить в игру. Однако, это актуально только для Mac OS 10.4 и выше, так как на iOS сборки мусора нет.
Определение класса
Теперь рассмотрим файл Complex.m с определением методов класса Complex:
Конструктор по умолчанию вызывает специализированный конструктор с определенными начальными параметрами. Метод complexWithRe:andIm: возвращает инициализированный объект класса Complex, размещенный в текущем самовыгружаемом пуле. То же самое делает и метод description, возвращая объект класса NSString. Вот пример программы, где используется класс Complex:
Категории и расширения
Если к уже написанному (а, возможно, и откомпилированному) классу нужно добавить\переопределить некоторые методы без наследования – категории позволяют это сделать без особых усилий:
А пользоваться этим можно вот так:
Расширения несут добрую службу как безымянные категории:
Протоколы
Протокол Objective-C – это формализованное объявление группы методов, которые, по желанию, может реализовать любой класс (аналог класса в С++, где все методы объявлены со спецификатором virtual … = 0). В версии языка 2.0 методы протокола могут быть требуемыми (спецификатор @required, он считается умалчиваемым) и выборочными (спецификатор @optional). Если какой либо класс реализовал требуемые методы протокола, то он называется классом, поддерживающим данный протокол. Протокол, и класс, его поддерживающий, объявляются вот так:
Oбъекту класса MyPrinter можно гарантированно посылать сообщения print и switchedOn, и, после проверки на respondsToSelector:, можно посылать сообщение loadPaper:, та как в его реализации должны присутствовать определения одноименных методов. Объявление объекта класса, поддерживающего какой-либо протокол осуществляется так:
Кроме того, один класс может удовлетворять нескольким протоколам. Для этого их можно перечислить через запятую в угловых скобках в объявлении класса.
А чтобы объявить объект неизвестного класса (id), соответствующий некоторому протоколу, пишут так:
Исключения
Есть два основных подхода к обработке ошибок: глобальная статусная переменная, значение которой информирует об успешности выполнения предыдущей операции, и генерация исключений. Суть обоих в том, что код, в котором произошла ошибка, надеется, что решить ее сможет вызвавший его код, поэтому возвращает управление ему, сообщая о произошедшей ситуации как можно более подробно. Objective-C поддерживает оба эти подхода.
Исключение – это объект некоторого класса. Он (даже своим типом) несет в себе некоторую информацию о произошедшей ситуации. Для удобства в Cocoa имеется класс NSException, который можно инициализировать двумя объектами NSString и одним объектом произвольного класса (тип id):
Сгенерировать исключение и, тем самым, запустить механизм раскрутки стека вызовов, можно с помощью оператора @throw. Чтобы перхватить сгенерированное исключение, участок кода, где возможна его генерация, необходимо заключить в специальный блок с заглавием try (такие блоки могут быть вложенными). А затем, после этого блока, поставить блок с заглавием catch(), где в круглых скобках указать тип предполагаемого исключения. Блоков catch() после блока try может быть несколько. После генерации исключения управление, раскручивая стек, выходит из блока try и, проверяя по очереди все блоки catch(), попадает именно в тот блок catch(), в фигурных скобках которого стоит такой тип, к которому тип исключения приводится неявно (точное совпадение, указатель на базовый класс или id). Если исключение по типу не совпало ни с одним блоком catch(), управление продолжает раскрутку стека. Если после блока с заглавием try стоит блок с заглавием finally, то управление передастся ему независимо от того, произошло ли в блоке try исключение (и обработан какой-нибудь блок catch()), или выполнилась его последняя инструкция. Ниже приведен пример работы с объектом класса Cup в методе fill которого происходит исключение:
В блоке finally удобно освобождать ресурсы, выделенные в блоке try, но не освобожденные по причине сгенерированного исключения.
Свойства
Для версии Objective-C 2.0 нашa реализация класса Complex явно избыточна: в ней слишком много методов доступа и их определение – сплошная рутина. Перепишем его с использованием свойств:
Свойство – это некоторое имя, доступное через указатель на объект посредством оператора точка “.”. Свойства используются вместо методов доступа чтобы получить или установить инвариант объекта. При объявлении свойства указывается рад параметров, описывающих особенности генерируемых свойством методов доступа.
- getter=getterName, setter=setterName Указывает, что метод доступа для чтения будет называться getterName, а для изменения — setterName
- readonly Не генерировать метод доступа для изменения
- readwrite Генерировать оба метода доступа
- assign Метод доступа на изменение реализовывать посредством простого присваивания
- retain Принимаемому значению послать сообщение retain, предыдущему значению инварианта послать release и присвоить ему принимаемое значение
- copy Использовать обычный оператор присваивания, но присвоить копию принимаемого значения (перед присваиванием емупосылается сообщение copy)
- nonatomic Не использовать внутренние блокировки для синхронизации нескольких нитей в сгенерированных методах доступа (по умолчанию cинхронизация используется)
Теперь в определении класса Complex нам не нужно вручную писать методы доступа. Они сгенерируются компилятором и будут идентичны тем, что были раньше.
Источник