2016-04-25 4 views
2

Я прилагаю все усилия, чтобы объяснить, как это работает, но это довольно запутанно и длительно. Дайте мне знать, если что-то я могу сделать, чтобы уточнить.Как применить KVO к @ динамическим свойствам, созданным во время выполнения?

Я застрял в концепциях KVC и KVO.
У меня есть класс ввода (NSObject).
Класс входа имеет частный переменный объектProperties (NSDictionary), значение которого исходит от сервера.

Предположим, что objectProperties имеет ключевую «цену», «скидку» и т. Д., Тогда я хочу создать динамические свойства в экземпляре класса Entry.

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

Теперь, когда пользователь хочет использовать KVO по тем же свойствам, они недоступны.

Для создания динамических свойств, и это Getter/сеттер:

-(NSString*)propName:(NSString*)name { 
    name = [name stringByReplacingOccurrencesOfString:@":" withString:@""]; 
    NSRange r; 
    r.length = name.length -1 ; 
    r.location = 1; 
    NSString* firstChar = [name stringByReplacingCharactersInRange:r withString:@""]; 
    if([firstChar isEqualToString:[firstChar lowercaseString]]) 
    {return name;} 
    r.length = 1; 
    r.location = 0; 
    NSString* theRest = [name stringByReplacingCharactersInRange:r withString:@""]; 
    return [NSString stringWithFormat:@"%@%@", [firstChar lowercaseString] , theRest]; 
} 

-(NSString*)setterName:(NSString*)name { 
    name = [self propName:name]; 
    NSRange r; 
    r.length = name.length -1 ; 
    r.location = 1; 
    NSString* firstChar = [name stringByReplacingCharactersInRange:r withString:@""]; 
    r.length = 1; 
    r.location = 0; 
    NSString* theRest = [name stringByReplacingCharactersInRange:r withString:@""]; 
    return [NSString stringWithFormat:@"set%@%@", [firstChar uppercaseString] , theRest]; 
} 


-(NSString*)propNameFromSetterName:(NSString*)name { 
    NSRange r; 
    r.length = 3 ; 
    r.location = 0; 
    NSString* propName = [name stringByReplacingCharactersInRange:r withString:@""]; 
    return [self propName:propName]; } 


-(NSString*)ivarName:(NSString*)name { 
    NSRange r; 
    r.length = name.length -1 ; 
    r.location = 1; 
    NSString* firstChar = [name stringByReplacingCharactersInRange:r withString:@""].lowercaseString; 

if([firstChar isEqualToString:@"_"]) 
     return name; 
    r.length = 1; 
    r.location = 0; 
    NSString* theRest = [name stringByReplacingCharactersInRange:r withString:@""]; 
    return [NSString stringWithFormat:@"_%@%@",firstChar, theRest]; } 


NSObject *getter(id self, SEL _cmd) 
{ 
    NSString* name = NSStringFromSelector(_cmd); 
    NSString* ivarName = [self ivarName:name]; 
    Ivar ivar = class_getInstanceVariable([self class], [ivarName UTF8String]); 
    return object_getIvar(self, ivar); 
} 

void setter(id self, SEL _cmd, NSObject *newObj) 
{ 
    NSString* name = [self propNameFromSetterName:NSStringFromSelector(_cmd)]; 
    NSString* ivarName = [self ivarName:name]; 
    Ivar ivar = class_getInstanceVariable([self class], [ivarName UTF8String]); 
    id oldObj = object_getIvar(self, ivar); 
    if (![oldObj isEqual: newObj]) 
    { 
     object_setIvar(self, ivar, newObj); 
     [newObj copy]; 
    } 
} 

-(NSDictionary *)createProperties:(NSArray *)propNames { 
    NSMutableDictionary* keys = [[NSMutableDictionary alloc]init]; 
    for(NSString* key in propNames) 
    { 
     NSString* propName = [self propName: key]; 
     NSString* iVarName = [self ivarName:propName]; 

     class_addIvar([self class], [iVarName UTF8String] , sizeof(NSObject*), log2(sizeof(NSObject*)), @encode(NSObject)); 

     objc_property_attribute_t a1 = { "T", "@\"NSObject\"" }; 
     objc_property_attribute_t a2 = { "&", "" }; 
     objc_property_attribute_t a3 = { "N", "" }; 
     objc_property_attribute_t a4 = { "V", [iVarName UTF8String] }; 
     objc_property_attribute_t attrs[] = { a1, a2, a3, a4}; 

     class_addProperty([self class], [propName UTF8String], attrs, 4); 
     class_addMethod([self class], NSSelectorFromString(propName), (IMP)getter, "@@:"); 
     class_addMethod([self class], NSSelectorFromString([self setterName:propName]), (IMP)setter, "[email protected]:@"); 

     id val = [self.objectProperties objectForKey:key]; 
     [keys setValue:val forKey:propName]; 
    } 
    return keys; 
} 

Но когда пользователь хочет наблюдать любые свойства, он не доступен в пользовательском классе.

Я смущен, как создавать динамические свойства и применять KVO.

Я также попытался сделать подкласс класса Entry ie (myEntry, который пользователь создает в конце) и определить все переменные там. но как мне установить его значение там? Поскольку я хочу, чтобы это свойство было прочитано только.

+0

Что вы в конечном итоге пытаетесь достичь? Есть, вероятно, более простые способы сделать это. Создание динамических свойств и методов во время выполнения не очень распространено. – jtbandes

+0

Пожалуйста, объясните, чего вы действительно хотите достичь? Может быть, краткое описание - это то, что мне нужно. –

+0

в основном у меня есть класс ввода с objectProperties как частная переменная NSDictionary. Я хочу сделать ключи внутри этого словаря в качестве свойств во время выполнения, поэтому, когда пользователь хочет наблюдать за изменениями в стоимости этого имущества, он будет уведомлен. Эти ключевые свойства объекта варьируются в зависимости от ответа JSON. Иногда ключи - это цена, скидка, описание продукта. И в другой раз они являются именем категории, описанием категории и т. Д. Для этого я хочу создать динамические свойства. –

ответ

1

Прежде всего: вы не можете создавать ivars после создания экземпляра класса. Это связано с тем, что объем памяти уже созданных экземпляров памяти изменится. Поэтому удивительно, что -createProperties: является методом экземпляра.

Дополнительно KVO работает путем подклассификации класса наблюдаемого экземпляра во время выполнения и назначения нового класса наблюдаемому экземпляру (isa-swizzling). Это, очевидно, проблема, если вы измените базовый класс после регистрации для KVO.

Однако все сказанное относится к автоматическому KVO. Вместо этого вы можете использовать ручной KVO. Просто добавьте уведомления KVO своим аксессуарам.

Но как прокомментировано: вы должны переосмыслить всю свою концепцию.

 Смежные вопросы

  • Нет связанных вопросов^_^