Что такое objc setAssociatedObject () и в каких случаях его следует использовать?



в проекте, который я взял на себя, оригинальный автор решил использовать objc_setAssociatedObject() и я не на 100% ясно, что это такое и почему они решили использовать его.



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



objc_setAssociatedObject

Задает связанное значение для данного объекта с помощью данного ключа и ассоциации политика.
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
параметры
object

Исходный объект для ассоциации.
key

Ключ к ассоциации.
value

Значение, связанное с ключом ключ для объекта. Передайте nil, чтобы очистить существующую связь.
policy

Политика для ассоциации. Возможные значения см. В разделе " Поведение ассоциативных объектов."



Итак, что именно делает эта функция и в каких случаях следует ли его использовать?





редактировать после прочтения ответов



так какой смысл в следующем коде?



Device *device = [self.list objectAtIndex:[indexPath row]];
DeviceViewController *next = [[DeviceViewController alloc] initWithController:self.controller
device:device
item:self.rootVC.selectedItem];
objc_setAssociatedObject(device, &kDeviceControllerKey, next, OBJC_ASSOCIATION_RETAIN);


какой смысл связывать устройство с контроллером вида, если это уже переменная экземпляра?

608   4  

4 ответов:

из справочных документов на Objective-C Runtime Reference:

вы используете Objective-C runtime функция objc_setAssociatedObject to создайте ассоциацию между одним объектом и еще. Функция принимает четыре параметры: исходный объект, ключ, значение и политика ассоциации постоянный. Ключ является пустым указателем.

  • ключ для каждой ассоциации должен быть уникальным. Типичный шаблон использование статического переменная.
  • политика указывает, назначен Ли Связанный объект,
    сохранил, или скопировал, и будь то
    ассоциация может быть сделана атомарно или
    не атомарно. Этот шаблон
    подобно тому, что из атрибутов
    объявленное свойство (см. " свойство
    Атрибуты Объявления"). Вы указываете политика для отношений с использованием константа (см.
    objc_AssociationPolicy и
    Ассоциативное Поведение Объекта).

установление связи между массивом и строкой

static char overviewKey;



NSArray *array =

    [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil];

// For the purposes of illustration, use initWithFormat: to ensure

// the string can be deallocated

NSString *overview =

    [[NSString alloc] initWithFormat:@"%@", @"First three numbers"];



objc_setAssociatedObject (

    array,

    &overviewKey,

    overview,

    OBJC_ASSOCIATION_RETAIN

);



[overview release];

// (1) overview valid

[array release];

// (2) overview invalid

в точке 1, обзор строки все еще действует, потому что Политика OBJC_ASSOCIATION_RETAIN указывает, что массив сохраняет связанный объект. Когда массив является освобожденный, однако (в пункте 2), обзор выпущен и так в этом дело также освобождено. Если вы попытаетесь, например, запишите значение обзор, вы создаете среду выполнения исключение.

objc_setAssociatedObject добавляет хранилище ключевых значений к каждому объекту Objective-C. Это позволяет хранить дополнительное состояние для объекта, не отраженное в его переменных экземпляра.

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

вот список вариантов использования для объектных ассоциаций:

первый: для добавления переменных экземпляра в категории. В общем эта техника есть посоветовал против, но вот это пример законного использования. Допустим, вы хотите смоделировать дополнительные переменные экземпляра для объектов, которые вы не можете изменить (речь идет об изменении самого объекта, т. е. без подклассов). Скажем, установка заголовка на UIImage.

// UIImage-Title.h:
@interface UIImage(Title)
@property(nonatomic, copy) NSString *title;
@end 

// UIImage-Title.m:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

static char titleKey;

@implementation UIImage(Title)
- (NSString *)title
{
    return objc_getAssociatedObject(self, &titleKey);
}

- (void)setTitle:(NSString *)title
{
    objc_setAssociatedObject(self, &titleKey, title, OBJC_ASSOCIATION_COPY);
}
@end

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


второй: динамическое добавление информации о состоянии к объекту, не охваченному переменными экземпляра, в сочетании с KVO.

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

один отличный пример, который иллюстрирует это этой библиотека, в которой ассоциативные объекты используются с код уведомления. Вот выдержка из кода (Примечание: это уведомление KVO не обязательно запускать, чтобы код в этой библиотеке работал.. скорее он помещен туда автором для удобства, в основном любой объект, который регистрируется на это, будет уведомлен через KVO о том, что с ним произошли изменения):

static char BOOLRevealing;

- (BOOL)isRevealing
{
    return [(NSNumber*)objc_getAssociatedObject(self, &BOOLRevealing) boolValue];
} 

- (void)_setRevealing:(BOOL)revealing
{
    [self willChangeValueForKey:@"isRevealing"];
    objc_setAssociatedObject(self, &BOOLRevealing, 
       [NSNumber numberWithBool:revealing], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self didChangeValueForKey:@"isRevealing"];
}

бонус: взгляните на это обсуждение/объяснение ассоциированных объектов Мэтта Томпсона, автора семенной библиотеки AFNetworking

чтобы ответить на ваш пересмотренный вопрос:

какой смысл связывать устройство с контроллером вида, если это уже переменная экземпляра?

есть несколько причин, почему вы можете сделать это.

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

лично я думаю, что очень редко нужно использовать низкоуровневые функции времени выполнения Objective-C. Это похоже на запах кода для меня.

Comments

    Ничего не найдено.