Ответ 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 должны быть написаны более тщательно, но этого должно быть достаточно в качестве примера того, как динамически добавлять формальное свойство во время выполнения.