2009-07-28 35 views
10

我有一個名爲Settings的對象,它繼承自NSMutableDictionary。當我嘗試初始化此對象時使用如何從NSDictionary繼承?

Settings *settings = [[Settings alloc] initWithContentsOfFile: @"someFile"] 

它返回NSCFDictionary類型的對象。因此,它不承認我的其他方法。例如,當我打電話選擇「保存」,它反對:

[NSCFDictionary save]: unrecognized selector sent to instance 0x524bc0 

當然,這是確定,當我初始化使用花園裏各種

Settings *settings = [[Settings alloc] init] 

我試圖再次施展它來設置,但那沒用。這看起來很簡單 - 我錯過了什麼?

謝謝

+0

當我讀第一句話時,我立即想到也許,而不是創建一個設置類,你可以使用NSUserDefaults?當然,我不知道NSUserDefaults是否會滿足您的需求,但它的目的是存儲設置,因此可能不需要構建自己的設置。只是一個想法。 – 2009-07-28 05:51:08

+0

謝謝。這聽起來像它會做我想要的。這不是我存儲的「默認」值,但這可能會很好。 – farhadf 2009-07-30 19:02:37

回答

18

NSDictionary是一個類集羣。這意味着從它的init方法返回的值不是一個NSDictionary,而是一個實現實際功能的子類。在幾乎所有情況下,最好給你的類一個NSDictionary作爲一個實例變量,或者簡單地在NSDictionary上定義一個類別。

+1

這樣的其他「類」(最值得注意的是)NSString,NSArray和NSSet。我偶爾會遇到有關「NSBigMutableString」的日誌語句,這些語句在我學習類集羣之前一直困擾着我。 =) – 2009-07-28 02:07:12

+0

我同意這一點。最好的可能是使用一個有一個關係,而不是一個關係。 (更喜歡組合而不是子類)。您可以通過覆蓋`-setValue:forKey:`和`-valueForKey:`等來使您的類像字典一樣執行。 – nielsbot 2013-07-24 18:45:21

16

查克關於NSDictionary(和Dave,擴展名,關於NSArray/Set/String)和類集是正確的。賠率是-[NSDictionary initWithContentsOfFile:]調用不同於-init的初始化程序,這就是爲什麼它將爲您的已分配Settings實例替換爲NSMutableDictionary的另一個子類。 (初始化動作時,從文件中讀取可以選擇的NSDictionary的特定的已知子類,以及從文件加載執行,等等)

我會附和Chuck的指導,這是幾乎總是更好用的組合物或類別比NSDictionary的繼承。很可能您可以用更簡單的方式完成類別所做的工作,並讓自己在過程中減少潛在的錯誤。考慮自己在決定子類之前警告過。

這就是說,NSDictionary和NSMutableDictionary都被設計爲支持子類化,並且在極少數情況下這是正確的。在嘗試之前,先考慮一下並且堅持下去。如果你覺得這對你的設計是正確的選擇,在這裏都知道,並根據需要做一些關鍵點:從NSDictionary

  1. 重寫以下原始的方法:
    • -count
    • -objectForKey:
    • -keyEnumerator
    • -initWithObjects:forKeys:count :(指定初始值)
  2. 從覆蓋以下原始的方法:
    • -setObject:forKey:
    • -removeObjectForKey:
  3. 如果你支持NSCoding,做到心中有數classForKeyedArchiverreplacementObjectForKeyedArchiver:(從NSObject的兩個實例方法) - 他們可以完全改變了你的類如何響應,並且你經常無意中繼承了NS(可變)字典中的一些奇怪行爲。 (您可以驗證,如果他們是通過設置一個斷點在他們身上,或執行這些調用超級打破自己的代碼的元兇。)

我在一個NSMutableDictionary子類實現了許多這些點我自己的。您可以check it out並使用代碼,但可能會對您有所幫助。一個特別幫助我(可能是解決您的問題的方法)是重載指定的初始化程序,該程序目前尚未記錄(Radar#7046209)。

需要記住的是,即使這些子彈覆蓋了最常見的用途,但始終存在邊緣情況和不太常用的功能。例如,-isEqual:-hash用於測試是否相等等。

3

如果您實際上閱讀了NSDictionary的規範(我知道是一種莽撞行爲),您會發現一個名爲「Subclassing Notes」的部分。在這裏面你會讀到:

如果你需要繼承NSDictionary中,你需要考慮到由一類爲代表的帳戶 集羣存在,因此是在該方法在概念上基於幾個 原始的方法:

initWithObjects:forKeys: 

count 

objectForKey: 

keyEnumerator 

在子類中,您必須覆蓋所有這些方法。

1

這個問題很老了,因爲大多數這些答案被張貼,蘋果已經推出了object subscripting,它允許你做出你自己的類的行爲更像NSMutableArrayNSMutableDictionary。這比上面討論的替代方案更簡單。

至少,你必須重寫這些方法:

//Array-style 
- (id)objectAtIndexedSubscript:(NSUInteger)idx; 
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx; 

//Dictionary-style 
- (id)objectForKeyedSubscript:(id <NSCopying>)key; 
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key; 

這裏是如何做到這一點很好tutorial