четверг, 30 апреля 2009 г.

30.04.09. T&T. Узнать, в каком классе упало приложение

Если нужно узнать, в каком классе произошло обращение к освобожденному указателю, то

Executables - Get Info - Arguments - Add Variable - NSZombieEnabled=YES

и при выполнении программы, когда появляется иконка GDB, то можно перейти в окно консоли, нажать Continue и увидеть, где возникла ошибка.

Также для обнаружения утечек памяти служит инструмент Leaks. (Run - Start with Performance Tool - Leaks).

30.04.09. Outlets, Delegates.

Outlets

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

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

Delegates and Data Sources

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

Делегирующий класс имеет у себя свойство или outlet с именем delegate.

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


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


- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename; // NSApplication
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url; // UIApplicationDelegate
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; // NSApplication
- (UITableRowIndexSet *)tableView:(NSTableView *)tableView willSelectRows:(UITableRowIndexSet *)selection; // UITableViewDelegate
- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame; // NSWindow

Имя обычно включает глаголы: “Should” or “Will” для событий, которые только должны произойти и “Did” or “Has”, которые уже произошли.

Если событие должно произойти, то делегат может на него повлиять, например, вернуть No для сообщения applicationShouldTerminate.

Для произошедших событий сообщения делегатам носят информирующий характер.


- (void) tableView:(NSTableView*)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn; // NSTableView
- (void)windowDidMove:(NSNotification *)notification; // NSWindow
- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame; // UIApplication
- (void)applicationWillBecomeActive:(NSNotification *)notification; // NSApplication

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

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

Сделать свой объект делегатом можно в IB, соединив outlet`а delegate с экземпляром своего объекта.

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

Пример: пусть у приложения есть контроллер и у окон этого приложения есть контроллер и они являются делегатами соответственно приложения и окна. Тогда найти контроллер окна можно так:

id winController = [[NSApp keyWindow] delegate];

А контроллер приложения так:

id appController = [NSApp delegate];

30.04.09. Object Modeling.

Entity-relationship modeling позволяет представить структуру данных в некотором источнике данных таким образом, чтобы данные можно было сопоставить объектам в ОО модели.

Object modeling - разновидность Entity-relationship modeling.

Сущности обладают атрибутами и отношениями с другими сущностями. Атрибуты + отношения - свойства. 

Атрибуты содержат данные. Эти данные могут находиться в переменных примитивных типов (integer, float, or double), структуры Си (array of char or an NSPoint), в экземплярах примитивных классов (NSNumber, NSData, or NSColor). Неизменяемые объекты (NSColor) тоже рассматриваются как атрибуты. 

Отношения указывают на другие сущности.

Отношения могут быть рефлексивными (от сущности к этой же сущности), однонаправленными и двунаправленными.

Кардинальность показывает ко скольким объектам одновременно может быть направлено отношение. Может быть от 0 до n или *.

Доступ к свойствам осуществляется по ключам. Все значения, полученные по ключу, одного типа. Если по ключу доступен объект, то возвращается объект. Если находится значение примитивного типа, то возвращается объект типа NSNumber or NSValue. 

Если отношение один-к-одному, то возвращается объект. Если один-ко-многим, то коллекция.

Key Paths

Сущность.Свойство.Свойство....

30.04.09. The Model-View-Controller Design Pattern

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

Представление не должно нести ответственность за сохранение информации.

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

Контроллеры интерпретируют действия над элементами интерфейса в действия над моделью.

Возможно объединение ролей: view-controller или model-controller.

Классическая реализация MVC:


Такой способ можно реализовать в Cocoa, использую технологию bindings, однако это свяжет представление с моделью, а они должны наиболее удобны для повторного использования. Поэтому в Cocoa всё взаимодействие идет через контроллер.


Напоминание: контроллеры могут быть медиаторами и координаторами.

Медиаторы (от NSController) просто переправляют запросы с помощью target-actions.

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

Обычно координаторы владеют медиаторами, которые сохраняются в nib-файл.



Design Guidelines for MVC Applications

В качестве контроллера можно использовать класс производный от NSController или от NSObject.

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

Наименее повторно используемы контроллеры, наиболее - классы представлений и модели.

NSController дает дополнительные возможности по сравнению с простой привязкой. Например, возможность отката изменений.

Предпочтительные зависимости:

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

Model-View-Controller in Cocoa (Mac OS X)

Document architecture.

Контроллер для всего приложения - NSDocumentController.

Контроллер для каждого из окон - NSWindowController.

Контроллер+модель - NSDocument.

Bindings.

NSController

среда, 29 апреля 2009 г.

29.04.09. Design Patterns. Memento, Наблюдатель, Прокси, Одиночка, Шаблонный метод

Memento

Сохраняет внутреннее состояние объекта, не нарушая инкапсуляции так, чтобы можно было позже восстановить его.

Применяется при архивировании объектов. Объекты при этом должны реализовывать протокол NSCoding. Для архивирования используется объект NSCoder и классы NSKeyedArchiver and NSKeyedUnarchiver.

В простых случаях возможно также сохранение объектов классов NSDictionary, NSArray, NSString, NSData, NSDate, and NSNumber в виде списка свойств. Этот способ работает только для графа объектов, состоящего из указанных классов.

Кроме того, для сложных графов объектов можно применять фреймворк Core Data.

Observer

Зависимость один-ко-многим.

Notifications

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

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

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

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

Key-Value Observing

Уведомление наблюдателей об изменениях в свойствах наблюдаемого объекта. Умедомление происходит напрямую без центрального объекта.

В MVC таким способом представление уведомляется об изменениях в модели.

Для работы с этим типом уведомлений объекты должны быть KVO-совместимыми.

Proxy

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

Для создания прокси можно использовать абстрактный класс NSProxy, который реализует протокол NSObject и поэтому его можно использовать как корневой объект.

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

Singleton

Единственный объект, имеющий доступ к ценному ресурсу. Создается при первом обращении.

Примеры:

NSFileManager, NSWorkspace, NSApplication

Template Method

Задает структуру алгоритма. Некоторые шаги могут быть переопределены в подклассах.

Document Architecture построена с использованием этого принципа, т.е. обычно нужно создать производные классы и в них переопределить некоторые методы, чтобы другие методы воспользовались переопределенным методом.

29.04.09. Design Patterns. Категории, фасад, итератор, медиатор

Categories

Категории являются еще одним способом расширить класс (только добавить поведение) без создания подкласса.

Этим способом можно также сгруппировать близкие по смыслу методы.

Категории добавляются к классу на этапе компиляции.

Facade

Предоставляет удобный доступ к подсистемам.

Пример: NSImage, который содержит несколько вариантов представлений изображений, которые автоматически выбираются в зависимости от разрешения и т.п.

Iterator

Перекладывает ответственность по работе с элементами коллекций с самих коллекций на специальные объекты-итераторы. Структура коллекции скрывается от клиента.

Производные от NSEnumerator классы задают поведение итератора для различных коллекций.

NSArray, NSSet, and NSDictionary имеют метод, возвращающий подходящий итератор. Работа с любым итератором задается методами NSEnumerator. Например, для получения очередного элемента нужно отправить сообщение nextObject.

Mediator

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

Контроллеры являются посредниками в MVC.

Контроллеры-медиаторы (производные от NSController) перенаправляют запросы от представления к модели. Поддерживают технологию привязок (bindings) элементов интерфейса к объектам модели. Экземпляры таких контроллеров доступны через IB и поэтому доступны для повторного использования.

NSObjectController - для управления одиночным объектом из модели.

NSArrayController - для управления набором объектов модели. Управляет выбором, добавлением и удалением.

NSTreeController - для управления иерархической структурой объектов модели.

NSUserDefaultsController - для управления настройками.

Контроллеры-координаторы централизуют взаимодействие между объектами. Обычно производны от NSWindowController или NSObject. Являются делегатами классов из фреймворка и целями (targets) для сообщений-действий. Из-за реализации под конкретную программу не взаимозаменяемы.

Без контроллеров-медиаторов связать можно любую пару объектов, если они реализуют неформальные протоколы NSKeyValueCoding and NSKeyValueObserving. Но лучше использовать явного посредника, производного от NSController.

Задачи координирующих контроллеров, решаемые через IB:

  • управляют outlets между объектами модели и объектами представления,
  • являются целями в схеме target-action, сообщения-действия инициируются элементами пользовательского интерфейса,
  • являются делегатами для классов фреймворка.

Все эти связи сохранются в nib-файл.

вторник, 28 апреля 2009 г.

28.04.09. Design Patterns. Абс. фабрика, адаптер, цепочка, команда, target-action, композит, делегат

How Cocoa Adapts Design Patterns

Два основных паттерна в Cocoa: “The Model-View-Controller Design Pattern” and “Object Modeling.”

Abstract Factory

Разновидность фабрики реализуется через Class Cluster.

Adapter

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

Интерфейс - как способ  скрыть конкретный класс.

Chain of Responsibility

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

Обычно такая цепочка получается в случае композиции элементов окон и представлений. Поиск обработчика начинается с самого нижнего объекта в иерархии и в конце концов может дойти до корнего объекта Window. Также сообщение может обработат делегат окна.

Цепочек может быть несколько, но только одна из них может быть активной.

Для организации объектов цепочки нужно использовать базовый класс NSResponder.

Command

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

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

The Target-Action Mechanism

Элемент управления (кнопка и т.п.) может послать сообщение целевому объекту (обычно контроллеру), в результате которого будет выполнено некоторое действие. Действие определяется селектором. Объект Cell элемента управления объединяет целевой объект и действие, т.е. обработчик сообщения. Элемент управления размещен в ячейке.

Composite

Используется в MVC при построении View. Корневым элементом является NSWindow. В нем находится Content View, прозрачная область покрывающая всю внутренную часть окна.



В итоге все View образуют иерархию представлений. Сообщение, отправленное представлению, также доходит и до его дочерних представлений.

Представление имеет две рамки: внешнюю frame и внутренню bounds.

Frame определяет положение представления относительно родительского представления.

Bounds задает координаты внутренней области представления.

Decorator

Воплощает принцип: класс должен быть открыт для расширения, но закрыт для изменения.

Delegation

Первый способ расширить класс (добавить поведение) без создания подкласса.

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

Хост-объект - обычно класс фреймворка. Делегирование - способ конкретизировать поведение такого класса без создания подкласса.

Делегат в Cocoa должен реализовывать методы формального или неформального протокола хост-класса. Хост-класс, прежде, чем отправить сообщение делегату, проверяет наличие метода с помощью respondsToSelector:.

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

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

Делегат может быть только один. Если нужно, чтобы о событиях в хост-классе уведомлялись несколько объектов, то нужно использовать механизм уведомлений (notifications).

пятница, 24 апреля 2009 г.

24.04.09. Design Patterns. Command

Cocoa Design Patterns

Решение задачи, находящейся в контексте.

Патерном описывается обобщенное решение задачи, достигающее некоторой цели при наличии ограничений. Задача рассматривается для определенного контекста.

Конкретная структура решения - "экземпляр" паттерна.

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

An Example: The Command Pattern


В Cocoa реализован в NSInvocation для промежуточного хранения отправленных сообщений (undo, состояния).


24.04.09. Ошибки, ресурсы

Error Handling

Исключения в Cocoa предназначены для незапланированных ошибок.

Для запланированных исключительных ситуаций (не открыт файл и т.п.) используется nil, NO, NULL. Чтобы сообщить дополнительную информацию об ошибке используется NSError.

Чтобы сообщить пользователю об ошибке можно использовать NSAlert.

Resource Management and Other Efficiencies

Ресурсы нужно использовать только по необходимости.

Для каждого copy и retain должен быть свой release.

Functions, Constants, and Other C Types

Для повышения производительности можно пользоваться средствами Си: функциями, структурами, enum-ами.

четверг, 23 апреля 2009 г.

23.04.09. The Foundation, Application Kit class hierarchy


Zooming in on the Cocoa architecture—some major dependencies



The Foundation class hierarchy






Overview of the Application Kit




23.04.09. Обязательные методы для подкласса.

Object Infrastructure

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

  • isEqual: and hash
  • description
  • copyWithZone:
  • initWithCoder: and encodeWithCoder:

23.04.09. Key-Value.

Key-Value Mechanisms

Существуют Key-value binding, key-value coding, and key-value observing.

  • KVB управляет привязками объектов друг к другу.
  • KVC c помощью реализации неформального протокола NSKeyValueCoding позволяет получить значение свойства по его имени через специальный метод этого протокола.
  • KVO c помощью реализации неформального протокола NSKeyValueObserving позволяет объектам регистрироваться в качестве наблюдателей за другим объектом. Наблюдаемый объект автоматически уведомит наблюдателей при изменении своих свойств.

Для того, чтобы сделать свойства объекта совместимыми с этой техникой:

  • в случае атрибутов или отношений 1-к-1 нужно для setter-а заводить метод setKey, а для getter-а - Key,
  • в случае свойства как отношения 1-ко-многим, т.е. коллекций в объекте, нужно getter-у давать имя свойства и если getter не должен возвращать изменяемую коллекцию, то нужно реализовать insertObject:inKeyAtIndex: and removeObjectFromKeyAtIndex: из NSKeyValueCoding.

Для автоматического KVO объект должен удовлетворять KVC.

23.04.09. Методы жизненного цикла. Свойства, getter-ы и setter-ы.

Basic Subclass Design

Объявление класса:



@interface Controller : NSObject {
// атрибуты
}
// методы
@end

При наследовании от некоторого полезного класса фреймворка придется переопределять некоторые методы. После этого нужно сделать так, чтобы эти методы были вызваны фреймворком вместе методов базового класса. В Interface Builder обычно для этого указывается порожденный класс вместе базового.

Instance Variables

Переменная с IBOutlet показывает, что внешние связи будут восстановлены автоматически при загрузке nib-файла.

Entry and Exit Points

Cocoa посылает объектам и классам, которые тоже являются объетком, в разные моменты жизни объекта определенные сообщения. 

  1. initialize. Сообщение получает класс. Это самое первое сообщение, получаемое классом до того, как сообщения получат экземпляры. Сначала сообщение получает суперклассы, затем подклассы. Обычно используется для инициализации некоторого общего состояния, используемого всеми экземплярами.
  2. init. Инициализация экземпляра. Может быть будет достаточно выделенного инициализатора суперкласса.
  3. initWithCoder:/encodeWithCoder: Используется при десериализации, сериализации.
  4. awakeFromNib. Посылается всем объектам, загружаемым из nib-файла, но после того, как будут созданы все экземпляры объектов. Это гарантирует, что можно будет установить все указатели IBOutlet для данного объекта.
  5. dealloc or finalize. Деструкторы.

Объект приложения NSApp посылает сообщения

  • applicationDidFinishLaunching:,
  • applicationWillFinishLaunching:,
  • applicationWillTerminate:

своему объекту-делегату, который может обработать эти ситуации.

Initialize or Decode?

Для сериализации/десериализации (архивирования, разархивирования) объект должен реализовать протокол NSCoding. При разархивировании ему будет послано сообщение initWithCoder:. Если объект нужно инициализировать не только при разархировании, то нужно написать обрабочик и для init.

Исключение: подкласс для класса фреймворка, связанный с Object в IB. В этом случае, экземпляру будет послано init, поэтому лучше всю инициализацию делать вообще в awakeFromNib.

Storing and Accessing Properties

Свойства могут быть двух видов: атрибуты и отношения.

Свойства могут  хранить экземпляры (т.е. не обязательно хранят).

Taking Advantage of Declared Properties

Возможны два способа работы со свойствами: в случае использования garbage collector (1) и в случае memory-managed code (2).

2: В свойствах setter должны быть заданы атрибуты retain или copy. При использовании NSCopying всегда нужно указывать copy.


1: Генерируются setter для name и getter для accountID.


@interface MyClass : NSObject {
NSString *name;
NSNumber *accountID;
}
@property (copy) NSString *name;
@property (readonly) NSNumber *accountID;
// ...
@end
@implementation MyClass
@synthesize name, accountID;
// ...
@end


2: Для currentHost в getter будет увеличивать счетчик ссылок. Для hidden будет сгенерирован getter с заданным именем.


@interface MyClass : NSObject {
NSHost *currentHost;
Boolean *hidden;
}
@property (retain, nonatomic) NSHost *currentHost;
@property (getter=isHidden, nonatomic) Boolean *hidden;
// ...
@end
@implementation MyClass
@synthesize name, hidden;
// ...
@end

Implementing Accessor Methods

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

Правила:

  • Полученный из getter объект можно безопасно использовать в области видимости вызвавшего getter метода. 
  • Вызывающий getter метод не должен релизить полученный объект в своей области видимости, не отправив ему предварительно retain или copy.


- (NSString *)title {
return title;
}
- (void)setTitle:(NSString *)newTitle {
if (title != newTitle) {
[title autorelease];
title = [newTitle copy];
}
}


В примере выше возможна опасная ситуация: клиент получит указатель на title и почти одновременно с этим будет вызван setter, который авторелизнет title. Через некоторое время пул будет очищен и title перестанет существовать. Клиент останется при этом с недействительным указателем.


Вариант лучше:


- (NSString *)title {
return [[title retain] autorelease];
}
- (void)setTitle:(NSString *)newTitle {
if (title != newTitle) {
[title release];
title = [newTitle copy];
}
}


Счетчик ссылок на title в getter-е увеличен на 1 и title будет послано 1 сообщение release, когда будет чиститься пул. Поэтому клиент останется с действительным указателем даже после [title release] в setter-е.


Когда посылать retain, а когда copy при передаче объектов?

Для этого нужно ответить на вопрос: что нужно получить, сам объект как таковой или его значение? Сам объект возможно изменит своё значение, но это не страшно, если нам нужна именно сущность. Конкретное значение, например, строки вероятно более важно, чем просто какая-нибудь строка.

Для setter-а можно рассуждать так. Если он устанавливает значение атрибута объекта, т.е. некое примитивное значение типа строки, числа или цвета, то это значение нужно скопировать из передаваемого параметра. Если же устанавливается отношение, т.е. отношение с другим объектом, то скорее всего нужно послать параметру retain.

Если придерживать "ленивого" использования атрибутов, т.е. вызывать getter только, когда атрибут понадобится, то его значение нужно устанавливать также в этом getter. Т.е. setter нельзя вызывать явно.

среда, 22 апреля 2009 г.

22.04.09. Наследование от классов Cocoa

Adding Behavior to a Cocoa Program

Основной координирующий объект приложения - NSApplicationMain. Он получает события, находит для них объекты-обработчики и так по кругу. 

Последовательность такая: объект создается, устанавливается autorealese пул, загружается интерфейс из nib-файла, управление передается пользователю, т.е. обрабатываются внешние события.

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

Фреймворк задает структуру и модель приложения. Для решения каждой задачи придется использовать столько классов, сколько предполагает фреймворк. 

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

В Cocoa есть классы, предоставляющие услуги

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

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

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

Делегаты и уведомления являются способами встраивания своего кода в фреймворк.

Cocoa API Conventions (некоторые)

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

Строки могут быть литералами (начинаются с @"") или константами. Предпочтительно использовать константные строки.

Метод, возвращающий значение атрибута, должен иметь имя атрибута, устанавливающий - начинаться с set, а затем имя атрибута с большой буквы.

Inheriting From a Cocoa Class

Значительная часть фреймворка имеет обобщенный вид (абстрактные классы). 

В Cocoa часто происходит так: метод моего класса вызывает определенный метод фреймворка, а он в свою очередь вызывает какой-то свой метод, переопределенный в моем классе.



Types of Overridden Methods

Готовым поведением можно воспользоваться, а можно переопределить его у себя в подклассе.

Некоторые методы имеют реализацию по умолчанию, возвращающую некоторое значение (YES или NO). Это значение определяет, включена или выключена некоторая возможность. Можно переопределить этот метод, чтобы переключить возможности.

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

Ну и конечно при обычном раскладе super-у сообщение посылать не нужно, нужно просто переопределить метод базового класса.

When to Make a Subclass

Нужно определить необходимый базовый класс (например, для MVC).

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

Также не стоит забывать о возможности композиции с одновременным наследованием от того же класса.

21.04.09. Изменяемость. Class Clusters. Категории, протоколы.

Cocoa - Изменяемость (mutability) объектов 

Некоторые классы неизменяемые, производные от них - изменяемые. 

Иногда предпочтительнее создать новый объект, чем изменять старый. 

Неизменяемые (immutable) лучше сделать, когда  данные объекта будут меняться значительно (NSString,NSData). 

Изменяемые (mutable) данные объекта будут меняться постепенно (массивы, коллекции). 

Изменяемые коллекции можно делать неизменяемыми сделав копию. Копия по умолчанию будет неизменяемая. Ее можно отдать клиенту. 

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

Могут быть проблемы, если хранить изменяемые объекты в коллекциях 

Cocoa - Class Clusters 

Кластеры объединяют классы, производные как private от абстрактного класса. В абстрактном классе есть метод создания экземпляра нужного подкласса. 

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

Остальные методы реализуются через методы-примитивы. 

Composite Object - декоратор. 

Cocoa - Категории, протоколы 
Категория - способ добавить методы к классу не создавая подклассов 

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

Категории можно назначить и NSObject. Добавленные методы будут присутствовать у всех объектов в программе.  

Неформальный протокол - это категория NSObject. Необязательно реализовывать все методы неформального протокола. Проверка реализации осуществляется через respondsToSelector:  

Протокол - аналог интерфейса 

Множественное наследование протоколов 

Проверка реализованности протокола у объекта 

20.04.09. Introspection. Сравнение объектов.

Cocoa - Introspection 

Обнародование информации объектом о себе во время выполнения. 

Поддержка протокола, место в иерархии, способность отвечать на сообщение. 

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

isMemberOfClass - только для класса аргумента. 

respondsToSelector - имеет ли объект реализацию метода? 
- (void)doCommandBySelector:(SEL)aSelector {
if ([self respondsToSelector:aSelector]) {
[self performSelector:aSelector withObject:nil];
} else {
[_client doCommandBySelector:aSelector];
}
}

conformsToProtocol - реализует протокол? 
- (void)doCommandBySelector:(SEL)aSelector {
if ([self respondsToSelector:aSelector]) {
[self performSelector:aSelector withObject:nil];
} else {
[_client doCommandBySelector:aSelector];
}
}

 

Сравнение объектов

 

hash - два одинаковых объекта имеют одинаковый хеш

isEqual - проверяет указатели на равенство

При самостоятельном определении стоит проверить:

  • равенство указателей 
  • совпадение классов
  • совпадение свойств объектов по значению 

Булевские значения - YES, NO

20.04.09. Создание объектов.

Cocoa - Создание объектов 


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


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


При инициализации объектов ссылками на др. объекты увеличивать счетчик ссылок.

 
Если вместо созданного объекта нужно вернуть ранее существовавший, то у созданного нужно уменьшить счетчик ссылок. 


При наследовании нужно следить, чтобы был init в производном классе, иначе вызовется только init родительского класса.  


designated initializer отправляет super сообщение, вызывающее у того designated initializer. 


designated initializer обычно имеет больше всех аргументов. 


Остальные инициализаторы вызывают друг друга или designated initializer. 


Вызовы designated инициализаторов образуют цепочку в иерархии классов. 


Наследуемые инициализаторы должны быть переопределены в производном классе так, чтобы вызывался designated initializer производного класса. 


В dealloc объекта сначала освобождаются агрегированные объекты, а затем посылается dealloc вверх по иерархии. 

Основные правила: 

  • Если ты владеешь объектом, то ты ответственен за его освобождение (release).

  • Никогда не релизь объект, которым не владеешь.

Счетчик числа ссылок показывает число владельцев объекта.

16.04.09. Создание объектов, частичное владение.

Cocoa - Создание объектов 
Частичное владение 

При передаче объекта от создателя другим объектам нужно увеличивать счетчик ссылок (retain), чтобы создатель не удалил объект, пока он нужен другим объектам. Другие объекты после того, как переданный объект перестал был нужен посылают ему release, т.е. уменьшают число ссылок на 1. 

Сообщение autorelease приводит к автоматической отправке сообщения release при очистке пула, в котором регистрируется autorelease-объект. Этому объекту будет отправлено столько сообщений release, сколько ему было послано сообщений autorelease. 

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

Если autorelease-объект гарантировано нужен получателю, то нужно увеличить на 1 счетчик ссылок перед отправкой объекта получателю (т.е. отправить и retain и autorelease). 

У объекта есть указатель isa на объект его класса. С помощью него выбирается метод, отвечающий на сообщение. 

Alloc инициализирует isa и устанавливается счетчик ссылок в 1 

init может инициализировать не только выделенный alloc объект

<16.04.09. Типы контроллеров.

Types of Cocoa Controller Objects 

Медиаторы - наследники NSController (NSObjectController, NSArrayController, NSUserDefaultsController, and NSTreeController) 

Координаторы - NSWindowController or NSDocumentController или наследники NSObject 

MVC as a Compound Design Pattern 
 

Координаторы управляют nib-файлом, в котором содержатся представления и медиаторы 

Other Cocoa Architectures on Mac OS X 

 

NSDocumentController управляет NSDocument, который управляет NSWindowController.  

NSWindowController - это представление-контроллер, контроллер владеет представлением. 

У документа может быть несколько окон. 

Документ - это модель-контроллер, контроллер владеет моделью