2011-05-03 42 views
4

我正在尋找一種將我的屬性直接設置爲作爲實例變量的NSMutableDictionary的簡寫方式。即:使用NSMutableDictionary作爲屬性的後備存儲

KVCModle.h:

@interface KVModel : NSObject { 
    NSMutableDictionary * data; 
} 
@property(nonatomic,assign)NSString * string1; 
@property(nonatomic,assign)NSString * string2; 
@end 

KVCModel.m

#import "KVModel.h" 


@implementation KVModel 

-(id)init 
{ 
    self = [super init]; 
    if(self) 
    { 
     data = [[NSMutableDictionary alloc] init]; 
    } 
    return self; 
} 

-(NSString *)string1 
{ 
    return [data objectForKey:@"string1"]; 
} 
-(NSString *)string2 
{ 
    return [data objectForKey:@"string2"]; 
} 
-(void)setString1:(NSString *)_string1 
{ 
    [data setObject:_string1 forKey:@"string1"]; 
} 
-(void)setString2:(NSString *)_string2 
{ 
    [data setObject:_string2 forKey:@"string2"]; 
} 
-(void)dealloc 
{ 
    [data release]; 
    [super dealloc]; 
} 

@end 

我試圖重寫setValue:ForKey:valueForKey:,但這些都是不叫,它們允許你直接設置屬性而不使用屬性語法。

我已經做出了預處理器宏來使這項工作在過去,但我根本沒有興趣打字,並且希望儘可能地避免在未來可能出現的情況。有沒有辦法讓我不熟悉的這項工作?

我曾考慮過使用NSManagedObject,但我不確定是否可以從中得到我想要的。 編輯: source

回答

8

如果你想使用類似foo = obj.fooobj.foo = foo的代碼訪問屬性,這就是爲什麼它不起作用。

屬性訪問語法與消息語法是同義的;前者與foo = [obj foo]完全相同,後者與[obj setFoo:foo]完全相同。沒有KVC代碼要攔截。屬性在語言級別; KVC處於框架級別。

您需要攔截訪問者消息。考慮實施the resolveInstanceMethod: class method,其中您通過使用Objective-C運行時API向該類添加方法實現來「解析」選擇器。您可以爲許多不同的選擇器添加相同的實現。爲了您的目的,有一個檢查選擇器(使用NSStringForSelector和常規NSString檢查技術)的函數或方法,並返回兩個事實:(1)屬性名稱,(2)它是否爲吸氣器(fooisFoo)或setter(setFoo:)。然後,還有兩種方法,一種是動態吸氣劑,另一種是動態吸氣劑。當選擇器命名一個getter時,將它添加到你的dynamic-getter方法中;當選擇器命名setter時,請使用動態設置器方法添加它。

那麼動態吸氣器和定位器方法是如何工作的呢?他們需要知道動態獲取和設置的屬性,但他們也需要不帶任何參數(getter)或一個參數(setter,該值取值),以便匹配原始屬性訪問消息。您可能想知道這些泛型實現如何知道要獲取或設置的屬性。答案是:它在選擇器中!用於發送消息的選擇器作爲隱藏參數_cmd傳遞給實現,因此請按照與之前相同的方式檢查該選擇器,以提取您應該動態獲取或設置的屬性的名稱。然後,動態獲取者應該發送[data objectForKey:keyExtractedFromSelector],動態設置者應該發送[data setObject:newValue forKey:keyExtractedFromSelector]

兩個注意事項:

  1. 當您使用屬性的訪問語法來訪問,你有沒有在類的@interface宣佈爲「財產」你仍然可以得到編譯器的投訴。這是正常的和故意的;你真的只應該使用屬性訪問語法來訪問已知的形式屬性。你在做什麼,雖然我發現解決它很有趣,但從技術上來說,它是對屬性訪問語法的濫用。
  2. 這隻適用於對象值。 KVC對原始值進行裝箱和拆箱,例如整數;因爲KVC不參與,沒有免費拳擊和拆箱。如果你已經聲明瞭正式的屬性(見1),你需要使用Objective-C運行時API進行反思,然後用你的研究結果進行裝箱和拆箱。
+0

嘿彼得 - 我發佈的代碼可以完成你所描述的任務。它也處理一些類型的裝箱/拆箱。 :) – nielsbot 2011-05-03 21:51:07

+0

@nielsbot:非常酷!之前我假設你正在做KVC特定的事情,但現在我看到你正在做我所描述的事情。我的道歉和+1。 – 2011-05-03 21:55:17

+0

謝謝。希望人們可以使用代碼。我將它用於可訪問NSDe​​faults替代的屬性語法。小心 - 我的代碼可能有錯誤...但我在生產中使用它。 – nielsbot 2011-05-03 21:57:53

3

,你基本上要的是你自己實現的NSManagedObject機械。我做了類似的事情。看看這裏:https://gist.github.com/954035 HTH

(更新代碼以消除對不存在的的NSString + Utilities.h的依賴)

(由失蹤ReleaseAndZero()宏)

+1

你可能想在你的帖子上註明它需要外部的NSString + Utilities.m – 2011-05-03 19:34:51

+0

doh ..讓我來修復它。謝謝。 – nielsbot 2011-05-03 19:36:45

+0

現在鏈接器似乎不知道ReleaseAndZero()是什麼。 – 2011-05-03 19:48:06

0

對於所有神聖的愛 - 不要使用NSDictionary作爲填充模型對象的每個可以想象的屬性的地方。 Ivars更容易調試,並且對其他開發人員(包括您未來的自己)更加清楚。

如果你想使用字典,使用字典和一些靜態定義的鍵 - 但如果你想有一個模型對象,使用一些高德

+0

但CALayer/CAAnimation和Javascript對象都以這種方式工作:) – nielsbot 2011-05-03 22:18:04

6

這激起了我的好奇心,所以我繼續使用彼得Hosey的建議重寫+resolveInstanceMethod:來生成getter和setter。我張貼的結果對象(DDDynamicStorageObject)到GitHub的庫:

https://github.com/davedelong/Demos

+0

剛剛抓住,做得好先生!我需要一點點挖掘,但我對此感到非常興奮。 – 2011-05-05 18:07:46

0

我同樣的問題走到今天就像你一樣。所以我在這裏發現你的問題。

上面的回答使用+resolveInstanceMethod:對我來說有點難。 :)

我的理解是,只要我們設置屬性,我們將有getter和setter方法,所以我使用setter方法來實現它。

BDLink.h

@property (nonatomic, strong) NSString *type; 
@property (nonatomic, strong) NSString *displayName; 
@property (nonatomic, strong) NSString *linkURI; 

BDLink.m

- (id)initWithLinkInfoDictionary:(NSDictionary *)linkInfoDict { 

    for (NSString *key in linkInfoDict) { 
     const char *rawName = [key UTF8String]; 
     NSString *setMethodString = [NSString stringWithFormat:@"set%c%s:", toupper(rawName[0]), (rawName+1)]; 
     SEL setMethod = NSSelectorFromString(setMethodString); 

     if ([self respondsToSelector:setMethod]) { 
      [self performSelector:setMethod withObject:linkInfoDict[key]]; 
     } 
    } 

    return self; 
} 

希望這將是有益的。我的第一個回答,:)

相關問題