Можно ли добавлять свойства объекту Objective C во время выполнения?
Как добавить свойства объекта во время выполнения?
Ответ 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. Конечно, это предполагает, что ваш класс использует соответствующий протокол.
Этот подход обычно используется для предоставления неизвестного поведения классам (например, селектор, который не существует).
Ответ 3
@properties - нет (т.е. с использованием точечного синтаксиса и т.д.). Но вы можете добавить хранилище, используя связанные объекты: Как использовать объект objc_setAssociatedObject/objc_getAssociatedObject внутри объекта?.