Подтвердить что ты не робот

Скрытые функции Objective-C

Objective-C получает широкое распространение благодаря использованию Apple для Mac OS X и iPhone. Каковы некоторые из ваших любимых "скрытых" функций языка Objective-C?

  • Одна функция для каждого ответа.
  • Приведите пример и краткое описание функции, а не ссылку на документацию.
  • Пометьте эту функцию, используя заголовок в качестве первой строки.
4b9b3361

Ответ 1

Метод Swizzling

В принципе, во время выполнения вы можете заменить одну реализацию метода другим.

Вот объяснение с кодом.

Один разумный вариант использования - для ленивой загрузки общего ресурса: обычно вы реализуете метод sharedFoo, приобретая блокировку, при необходимости создавая foo, получая его адрес, освобождая блокировку, а затем возвращаете foo. Это гарантирует, что foo создается только один раз, но каждый последующий доступ тратит время с блокировкой, которая больше не нужна.

С помощью метода swizzling вы можете сделать то же самое, что и раньше, за исключением того, что после создания foo используйте swizzling для замены первоначальной реализации sharedFoo со второй, которая не выполняет никаких проверок, и просто возвращает foo, который мы теперь знаем, был создан!

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

Ответ 2

Позирует

Objective-C позволяет классу полностью заменить другой класс внутри приложения. Заменяющий класс называется "представлять как" целевой класс. Все сообщения, отправленные в целевой класс, затем принимаются классом posing. Есть некоторые ограничения, по которым классы могут представлять:

  • Класс может представлять только один из его прямых или косвенных суперклассов
  • Класс posing не должен определять новые переменные экземпляра, отсутствующие в целевом классе (хотя он может определять или переопределять методы).
  • Перед созданием сообщения не должны отправляться сообщения в целевой класс.

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

  • Класс posing может вызывать переопределенные методы через super, таким образом включая реализацию целевого класса.
  • Класс posing может переопределять методы, определенные в категориях.

Пример:

@interface CustomNSApplication : NSApplication
@end

@implementation CustomNSApplication
- (void) setMainMenu: (NSMenu*) menu
{
     // do something with menu
}
@end

class_poseAs ([CustomNSApplication class], [NSApplication class]);

Это перехватывает каждое обращение setMainMenu к NSApplication.

Ответ 3

Пересылка объекта/метод отсутствует

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

-(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 Карманная ссылка

Это очень мощный инструмент и широко используется в сообществе Ruby для различных DSL и рельсов и т.д. Возникла в Smalltalk, которая повлияла как на Objective-C, так и на Ruby.

Ответ 4

Переключение ISA

Необходимо переопределить все поведение объекта? Фактически вы можете изменить класс активного объекта с помощью одной строки кода:

obj->isa = [NewClass class];

Это изменяет класс, получающий вызовы метода для этого объекта; он не изменяет расположение объекта в памяти. Таким образом, это действительно полезно, когда у вас есть набор классов с одинаковыми ivars (или один с подмножеством других), и вы хотите переключаться между ними.

Один кусок кода, который я написал, использует для ленивой загрузки: он выделяет объект класса A, заполняет пару критических иваров (в данном случае, главным образом, номер записи) и переключает указатель isa на укажите LazyA. Когда вызывается какой-либо метод, отличный от очень небольшого набора, такого как release и retain, LazyA загружает все данные с диска, заканчивает заполнение ivars, переключает указатель isa обратно на A и пересылает вызов реального класса.

Ответ 5

#include <Foundation/Debug.h>

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

Ответ 6

Категории

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

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

Ответ 7

Objective-C Справочник по времени выполнения

Легко забыть, что синтаксический сахар Objective-C преобразуется в нормальные вызовы функций C, которые являются объектами Object-C Runtime. Вероятно, вам никогда не понадобится вникать и использовать что-либо во время выполнения. Вот почему я считаю это "скрытой функцией".

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

Скажем, что кто-то разрабатывает внешний API рамки, который будет использоваться третьими лицами. И кто-то проектирует класс в рамках, который абстрактно представляет пакет данных, мы назовем его MLAbstractDataPacket. Теперь это относится к приложению, которое связывает структуру с подклассом MLAbstractDataPacket и определяет пакеты данных подкласса. Каждый подкласс должен переопределять метод +(BOOL)isMyKindOfDataPacket:(NSData *)data.

С учетом этой информации...

Было бы неплохо, если MLAbstractDataPacket предоставил удобный метод, который вернул правильный инициализированный класс для пакета данных, который приходит в форме +(id)initWithDataPacket:(NSData *)data.

Здесь есть только одна проблема. Суперкласс не знает ни о каком из своих подклассов. Таким образом, здесь вы можете использовать метод runtime objc_getClassList() вместе с objc_getSuperclass(), чтобы найти классы, которые являются подклассами MLAbstractDataPacket. После того, как у вас есть список подклассов, вы можете попробовать +isMyKindOfDataPacket: на каждом, пока он не будет найден или не найден.

Информацию об этом можно найти на http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html.

Ответ 8

Мне нравится подробный метод, называемый как [myArray writeToFile:myPath atomically:YES], где каждый аргумент имеет метку.