Скрытые возможности Objective-C
Objective-C получает все более широкое распространение благодаря использованию Apple для Mac OS X и iPhone. Каковы некоторые из ваших любимых "скрытых" особенностей языка Objective-C?
- Одна особенность за ответ.
- Приведите пример и краткое описание функции, а не просто ссылку на документацию.
- Пометьте объект, используя заголовок в качестве первой строки.
8 ответов
Метод Swizzling
По сути, во время выполнения вы можете поменять одну реализацию метода на другую.
Один умный вариант использования для отложенной загрузки общего ресурса: обычно вы реализуете sharedFoo
метод получения блокировки, создания foo
если необходимо, получить его адрес, снять блокировку, а затем вернуть foo
, Это гарантирует, что foo
создается только один раз, но каждый последующий доступ тратит время с блокировкой, которая больше не нужна.
С методом Swizzling, вы можете сделать то же самое, что и раньше, за исключением foo
был создан Swizzling, чтобы поменять начальную реализацию sharedFoo
со вторым, который не проверяет и просто возвращает foo
что мы теперь знаем, был создан!
Конечно, метод swizzling может привести к неприятностям, и могут быть ситуации, когда приведенный выше пример - плохая идея, но эй... вот почему это скрытая функция.
позирует
Objective-C позволяет классу полностью заменить другой класс в приложении. Говорят, что замещающий класс "представляет собой" целевой класс. Все сообщения, отправленные целевому классу, затем принимаются классом позирования. Есть некоторые ограничения на то, какие классы могут представлять:
- Класс может выдавать себя за одного из своих прямых или косвенных суперклассов.
- Класс представления не должен определять никаких новых переменных экземпляра, которые отсутствуют в целевом классе (хотя он может определять или переопределять методы).
- Никакие сообщения не должны были быть отправлены в целевой класс до постановки.
Позиционирование, подобно категориям, позволяет глобально расширять существующие классы. Изложение разрешает две особенности, отсутствующие в категориях:
- Класс позирования может вызывать переопределенные методы через super, включая реализацию целевого класса.
- Класс позирования может переопределять методы, определенные в категориях.
Пример:
@interface CustomNSApplication : NSApplication
@end
@implementation CustomNSApplication
- (void) setMainMenu: (NSMenu*) menu
{
// do something with menu
}
@end
class_poseAs ([CustomNSApplication class], [NSApplication class]);
Это перехватывает каждый вызов setMainMenu для NSApplication.
Переадресация объекта / метод отсутствует
Когда объекту отправляется сообщение, для которого у него нет метода, система времени выполнения дает ему еще один шанс обработать вызов, прежде чем отказаться. Если объект поддерживает -forward:: метод, среда выполнения вызывает этот метод, передавая ему информацию о необработанном вызове. Возвращаемое значение от переадресованного вызова передается обратно исходному вызывающему методу.
-(retval_t)forward:(SEL)sel :(arglist_t)args {
if ([myDelegate respondsTo:sel])
return [myDelegate performv:sel :args]
else
return [super forward:sel :args];
}
Содержимое из Objective-C Pocket Reference
Это очень мощный инструмент, который активно используется в сообществе Ruby для различных DSL, рельсов и т. Д. Создан в Smalltalk, который повлиял как на Objective-C, так и на Ruby.
ISA Switching
Нужно переопределить все поведение объекта? Вы можете изменить класс активного объекта с помощью одной строки кода:
obj->isa = [NewClass class];
Это только изменяет класс, который получает вызовы метода для этого объекта; это не меняет расположение объекта в памяти. Таким образом, это действительно полезно только тогда, когда у вас есть набор классов с одинаковыми ivars (или один с подмножеством других), и вы хотите переключаться между ними.
Один фрагмент кода, который я написал, использует это для отложенной загрузки: он выделяет объект класса A
, заполняет пару критических иваров (в данном случае, в основном, это номер записи) и переключает isa
указатель для указания на LazyA
, Когда любой метод, кроме очень маленького набора, как release
а также retain
называется, LazyA
загружает все данные с диска, завершает заполнение иваров, переключает isa
указатель назад на A
и переадресует вызов в реальный класс.
категории
Используя категории, вы можете добавлять методы во встроенные классы без создания подклассов. Полная ссылка.
Приятно добавлять удобные методы в обычно используемые классы, такие как NSString или NSData.
#include <Foundation/Debug.h>
Множество инструментов для того, чтобы отследить утечки памяти, преждевременные освобождения и многое другое в этом заголовочном файле.
Objective-C Runtime Ссылка
Легко забыть, что синтаксический сахар Objective-C преобразуется в обычные вызовы функций C, которые являются средой выполнения Object-C. Вполне вероятно, что вам никогда не нужно будет углубляться и использовать что-либо во время выполнения. Вот почему я считаю это "скрытой функцией".
Позвольте мне дать способ, которым можно использовать систему времени выполнения.
Допустим, кто-то разрабатывает API-интерфейс для внешней среды, который будет использоваться третьими сторонами. И что кто-то разрабатывает класс в рамках, который абстрактно представляет пакет данных, мы назовем его MLAbstractDataPacket
, Теперь дело за приложением, которое связывает в рамках с подклассом MLAbstractDataPacket
и определить пакеты данных подкласса. Каждый подкласс должен переопределять метод +(BOOL)isMyKindOfDataPacket:(NSData *)data
,
Имея в виду эту информацию...
Было бы хорошо, если MLAbstractDataPacket
предоставил удобный метод, который возвратил правильный инициализированный класс для пакета данных, который приходит в форме +(id)initWithDataPacket:(NSData *)data
,
Здесь только одна проблема. Суперкласс не знает ни о одном из своих подклассов. Так что здесь вы можете использовать метод времени выполнения objc_getClassList()
вместе с objc_getSuperclass()
чтобы найти классы, которые являются подклассами MLAbstractDataPacket. Как только у вас есть список подклассов, вы можете попробовать +isMyKindOfDataPacket:
на каждом, пока один не найден или не найден.
Справочную информацию об этом можно найти по адресу http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html.
Мне нравится многословный метод именования [myArray writeToFile:myPath atomically:YES]
где каждый аргумент имеет метку.