четверг, 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).