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

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

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

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

objc_setAssociatedObject
Устанавливает связанное значение для данного объекта с использованием заданной политики ключа и ассоциации.
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
Параметры
object
Исходный объект для ассоциации.
key
Ключ для ассоциации.
value
Значение, связанное с ключом для объекта. Передайте нуль, чтобы очистить существующую ассоциацию.
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);

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

4b9b3361

Ответ 1

Из справочных документов на Objective-C Справочная информация по времени:

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

  • Ключ каждой ассоциации должен быть уникальным. Типичная модель используйте статическую переменную.
  • Политика определяет, назначен ли связанный объект,
    сохранены или скопированы, а также ассоциация выполняется атомарно или
    без атомарно. Этот шаблон аналогично атрибутам объявленное свойство (см. "Свойство
    Атрибуты декларации" ). политика использования отношений константа (см. 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), обзор выпущен, и поэтому в этом случай также освобожден. Если вы попытаетесь, например, запишите значение обзор, вы создаете среду выполнения исключение.

Ответ 2

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

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

При использовании правильной политики ассоциации ваши объекты будут освобождены при освобождении основного объекта.

Ответ 3

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

one: Чтобы добавить переменные экземпляра в категории. В общем, этот метод рекомендуется, но вот пример законного использовать. Предположим, вы хотите имитировать дополнительные переменные экземпляра для объектов, которые нельзя изменить (мы говорим об изменении самого объекта, т.е. без подкласса). Скажем, установив название на 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.


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

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

Один отличный пример, иллюстрирующий это эта библиотека, в которой ассоциативные объекты используются с 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"];
}

бонус: взгляните на это обсуждение/объяснение связанных объектов Mattt Thompson, автором семенная библиотека AFNetworking

Ответ 4

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

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

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

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

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