2016-04-25 3 views
2

私はこれがどのように機能するのかを説明するために最善を尽くしていますが、それは非常に混乱し、時間がかかります。明確にするために私ができることがあれば教えてください。実行時に作成された@dynamicプロパティにKVOを適用する方法は?

私はKVCとKVOの概念に没頭しています。
私はEntry Class(NSObject)を持っています。
エントリクラスには、プライベート変数objectProperties(NSDictionary)があり、その値はサーバから取得されます。

objectPropertiesに "price"、 "discount"などのキーがあるとすると、Entryクラスのインスタンスで動的プロパティを作成したいとします。

これらのキーは、応答や動的変数によって異なる場合があります。

ユーザーは、同じプロパティでKVOを使用する場合、アクセスできません。動的プロパティを作成するための

、それはゲッター/セッターです:

-(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クラスのサブクラス(つまり、ユーザーが最後に作成するmyEntry)を作成し、そこにすべての変数を定義してみました。しかし、私はそこでその価値をどのように設定するのですか?私はそのプロパティをreadOnlyにしたい。

+0

あなたは最終的に達成しようとしていますか?それを行う簡単な方法があります。実行時に動的なプロパティとメソッドを作成することはあまり一般的ではありません。 – jtbandes

+0

本当に達成したいことを説明してください。私が必要とするのは簡単な説明かもしれません。 –

+0

基本的に私はobjectPropertiesを持つエントリクラスをNSDictionaryのプライベート変数として持っています。この辞書の中のキーを実行時にプロパティとしてプロパティに設定したいので、ユーザーがそのプロパティの値の変更を監視したい場合、通知されます。これらのkeysof objectPropertiesは、JSONレスポンスが変化するにつれて変化します。時にはキーは価格、割引、製品の説明です。カテゴリ名、カテゴリの説明などです。そのために、私は動的なプロパティを作成したいと思っています。 –

答えて

1

まず最初に、クラスをインスタンス化した後、イーグルスを作成することはできません。これは、すでに作成されたインスタンスのメモリフットプリントが変更されるためです。したがって、-createProperties:がインスタンスメソッドであることは驚くべきことです。

さらに、KVOは、実行時に観測されたインスタンスのクラスをサブクラス化し、観測されたインスタンスに新しいクラスを割り当てる(isa-swizzling)ことによって動作します。 KVOに登録した後に基本クラスを変更すると、明らかに問題になります。

ただし、すべてが自動KVOに適用されます。代わりに手動KVOを使用できます。アクセサーにKVO通知を追加するだけです。

コメント:あなたの全体のコンセプトを再考する必要があります。

関連する問題