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

Как добавить свойства объекта во время выполнения?

Можно ли добавлять свойства объекту Objective C во время выполнения?

4b9b3361

Ответ 1

Его можно добавить формальные свойства в класс через class_addProperty():

BOOL class_addProperty(Class cls,
    const char *name,
    const objc_property_attribute_t *attributes,
    unsigned int attributeCount)

Первые два параметра являются само собой разумеющимися. Третий параметр - это массив атрибутов свойств, и каждый атрибут свойства представляет собой пару имя-значение, которая следует за Objective-C типом кодирования для объявленные свойства. Обратите внимание, что в документации по-прежнему упоминается строка с разделителями-запятыми для кодирования атрибутов свойств. Каждый сегмент в разделенной запятой строке представлен одним экземпляром objc_property_attribute_t. Кроме того, objc_property_attribute_t принимает имена классов помимо общей @ кодировки типа id.

Вот первый проект программы, который динамически добавляет свойство под названием name к классу, у которого уже есть переменная экземпляра, называемая _privateName:

#include <objc/runtime.h>
#import <Foundation/Foundation.h>

@interface SomeClass : NSObject {
    NSString *_privateName;
}
@end

@implementation SomeClass
- (id)init {
    self = [super init];
    if (self) _privateName = @"Steve";
    return self;
}
@end

NSString *nameGetter(id self, SEL _cmd) {
    Ivar ivar = class_getInstanceVariable([SomeClass class], "_privateName");
    return object_getIvar(self, ivar);
}

void nameSetter(id self, SEL _cmd, NSString *newName) {
    Ivar ivar = class_getInstanceVariable([SomeClass class], "_privateName");
    id oldName = object_getIvar(self, ivar);
    if (oldName != newName) object_setIvar(self, ivar, [newName copy]);
}

int main(void) {
    @autoreleasepool {
        objc_property_attribute_t type = { "T", "@\"NSString\"" };
        objc_property_attribute_t ownership = { "C", "" }; // C = copy
        objc_property_attribute_t backingivar  = { "V", "_privateName" };
        objc_property_attribute_t attrs[] = { type, ownership, backingivar };
        class_addProperty([SomeClass class], "name", attrs, 3);
        class_addMethod([SomeClass class], @selector(name), (IMP)nameGetter, "@@:");
        class_addMethod([SomeClass class], @selector(setName:), (IMP)nameSetter, "[email protected]:@");

        id o = [SomeClass new];
        NSLog(@"%@", [o name]);
        [o setName:@"Jobs"];
        NSLog(@"%@", [o name]);
    }
}

Его (обрезанный) выход:

Steve
Jobs

Методы getter и setter должны быть написаны более тщательно, но этого должно быть достаточно в качестве примера того, как динамически добавлять формальное свойство во время выполнения.

Ответ 2

Если вы посмотрите на NSKeyValueCoding протокол, зарегистрированный здесь, вы увидите, что есть сообщение с именем:

- (id)valueForUndefinedKey:(NSString *)key

Вы должны переопределить этот метод, чтобы предоставить свой пользовательский результат для указанного свойства undefined. Конечно, это предполагает, что ваш класс использует соответствующий протокол.

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