2013-02-24 67 views
2

我想弄清楚如何創建一個NSMutableDictionary保留而不是複製其密鑰。我已經實現 - (NSUInteger)哈希和 - (id)isEqual:對於我想要的鍵,我只是無法找出哪些選項要在回調中指定。NSMutableDictionary,保留其鍵

CFDictionaryKeyCallBacks keyCallbacks = { 0, NULL, NULL, CFCopyDescription, CFEqual, NULL }; 


self.commonParents = (NSMutableDictionary*)CFBridgingRelease(CFDictionaryCreateMutable(nil, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks)); 

上面的代碼工作正常在ARC使用弱引用到鑰匙,但如果我想要的強引用?關鍵回調應該是什麼樣子?

+4

爲什麼你覺得有必要改變字典如何處理它的密鑰?爲什麼你的代碼依賴於被保留的鍵而不是被複制?如果我們知道你爲什麼要這樣做,可能會有更好的解決方案。 – rmaddy 2013-02-24 18:28:33

+3

我第二個rmaddy的問題。此外,如果使用非標準字典,則CFDictionary不再安全地轉換爲「NSMutableDictionary *」。這些類型之間的免費橋接隱式依賴於使用標準CFType回調函數的CFDictionary。最後,你看看'NSMapTable'嗎? – 2013-02-24 18:36:37

+0

我遇到過足夠的情況,我曾經想過在'NSDictionary'周圍有些不同的內存管理語義,這似乎不合理。 – 2013-02-24 18:45:16

回答

5

TL;博士:

創建提供的默認回調函數的CFDictionaryRef。它會做你想做的。只是不要稱它爲NSDictionary


是的,你可以創建一個CFDictionaryRef保留其鍵和不復制它們。這實際上是CFDictionaryRef的的默認行爲

CFDictionaryCreateMutable()文檔說:

如果字典只包含CFType對象,然後將指針傳遞給kCFTypeDictionaryKeyCallBacks爲這個參數使用默認的回調函數。

(所以如果你只打算在投入正常的Objective-C對象到像void *指針或任何陣列,而不是隨意的事情,這是你想要的)

而對於kCFTypeDictionaryKeyCallBacks文檔如下所示:

預定義CFDictionaryKeyCallBacks結構包含適用於CFDictionary的鍵都是CFType派生對象時適用的一組回調。 保留回調爲CFRetain,發佈回調爲CFRelease,複製回調爲CFCopyDescription,等價回調爲CFEqual。因此,如果在創建字典時使用指向此常量的指針,則在添加到集合時鍵會自動保留,並在從集合中刪除時釋放。

注意,retain回調CFRetain(),而不是像CFCopyObject(實際上不存在)。實際上,Core Foundation沒有「複製任何對象」的規範方式,這就是爲什麼存在像CFStringCreateCopy,CFArrayCreateCopy,CGPathCreateCopy等功能的原因。

所以,你所能做的就是創造你的字典裏是這樣的:

CFDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 

而且您現在可以保留其鍵和不復制他們的字典。

我打算把在大字母下面一點,讓你神交我要告訴你:

您創建這本詞典是不是一個NSDictionary

是的,NSDictionaryCFDictionaryRef是免費橋接的。但投射這種CFDictionaryRefNSDictionary將是橋接的濫用,因爲該行的NSDictionary文檔中的:

...一鍵可以是任何對象(只要它符合NSCopying協議看下文)

類似地,對於-[NSMutableDictionary setObject:forKey:]文檔明確地說:

密鑰被複制(用copyWithZone:;鍵必須符合NSCopy ing協議)。

在字典中的鍵沒有符合<NSCopying>和使用-copyWithZone:不會被複制,這意味着你的字典是不是NSDictionary(或NSMutableDictionary)。無論何時您看到代碼中使用的NSDictionary,您都應該提供鍵值爲複製(未保留)的鍵值映射。這是API合約。做任何事情都可能導致未定義的行爲。

(某些對象覆蓋-copyreturn [self retain]事實上是一個實現細節和不相關的「什麼是NSDictionary」的討論。)

0

我的建議是,而不是這樣做,你的子類NSString或任何類您使用的關鍵,並重寫複製方法,它會返回保留的字符串,而不是一個複製的字符串。

+1

這會導致其他代碼實際需要的各種問題 – rmaddy 2013-02-24 18:26:25

+0

我認爲這是一個可能的解決方案,但我擔心會有更廣泛的後果,因爲這樣做通常不是一個好主意。如果指定正確,不應該使用KeyCallbacks? – ecbtln 2013-02-24 18:26:57

+4

如果對象是不可變的,這是一個合適的解決方案。例如,' - [NSString copy]'本質上只是'return [self retain]',但是' - [NSString mutableCopy]'做了一個完整的副本。但是,如果對象是可變的,那麼'copy'方法應該返回一個副本。 – 2013-02-24 18:44:27

0

我認爲有2種可能的解決方案,可以使用普通的舊的NSMutableDictionary來實現。它們不像NSMapTable那樣優雅。
您聲明您的每個密鑰都有uniqueID,因此我認爲此值不會隨着時間而改變。

選項1
使用您的實際鍵的uniqueID是一個NSMutableDictionary的,將存儲的@[key, value] NSArray的關鍵,因此整體結構看起來像這樣
@{ key1.uniqueID : @[key1, value1], key2.uniqueID : @[key2 : value2] }

選項2
製作NSObject的一個子類,它是選項1的包裝。或選項1上的任何變體。

這些是唯一有效的,如果uniqueID永遠不會改變

1

我認爲最好的答案是埋在評論,所以我這裏將突出顯示它:最簡單的方法是使用(或者可能是weak引用的變體之一)。