iOS 集合如何弱引用對象

一. 使用 NSValue

NSValue 可以弱引用保存一個對象磷箕,我們可以使用這種方法間接的引用。


NSMutableArray *array = @[].mutableCopy;
// 添加
NSObject *obj = [NSObject new];
[array addObject:[NSValue valueWithNonretainedObject:obj]];
// 讀取
NSValue *value = array[0];
NSObject *obj2 = [value nonretainedObjectValue];

注意:使用 NSValue 的方式,確實可以實現(xiàn)對對象的弱引用(即被添加到集合中時傲隶,對象的引用計數(shù)不會+1),但是當對象被釋放的時候窃页,數(shù)組中對應的對象會變成野指針跺株,因此需要手動刪除 NSArray 中對應對象的值,否則會在執(zhí)行 [value nonretainedObjectValue] 時崩潰脖卖;而使用 NSPointerArray 不會有這個問題乒省,對象的釋放會使得集合中的對象變?yōu)?NULL

二. 使用 NSPointerArray,NSMapTable畦木,NSHashTable

在iOS6.0之后出現(xiàn)了NSPointerArray袖扛,NSMapTable,NSHashTable十籍。
用法分別對應 NSMutableArray蛆封,NSMutableDictionary,NSMutableSet妓雾。

- 1. NSPointerArray

特性介紹

NSPointerArray 是 NSArray 的通用版本娶吞,和 NSArray/NSMutableArray 不同的是,NSPointerArray 具有下面這些特性:

  • 與 NSArray/NSMutableArray 相對應械姻,NSArray/NSMutableArray 強引用集合對象
  • NSPointerArray 可以弱引用集合對象妒蛇,一旦對象沒人持有了机断,NSPointerArray 中對應的項會被變成 NULL
  • NSPointerArray 是可變的,沒有不可變的版本
  • NSPointerArray 可以存儲 NULL绣夺,NULL 參與 count 計算
  • NSPointerArray 的 count 可以被設置吏奸,如果直接設置 count,多余的位置會使用 NULL 占位
  • NSPointerArray 存儲的是指針類型 void * 而不是對象陶耍,所以需要 __bridge 進行轉換
  • 使用 addPointer 和 pointerAtIndex 來存取指針
- (instancetype)initWithOptions:(NSPointerFunctionsOptions)options;
- (instancetype)initWithPointerFunctions:(NSPointerFunctions *)functions;

NSPointerFunctionsOptions 枚舉定義著內(nèi)存管理策略奋蔚、方法特性和內(nèi)存標識,以下是幾個常用的枚舉值:
內(nèi)存管理策略:
NSPointerFunctionsStrongMemory:強引用成員
NSPointerFunctionsMallocMemory: 用于 Mach 的 虛擬內(nèi)存管理
NSPointerFunctionsMachVirtualMemory: 用于 Mach 的 虛擬內(nèi)存管理
NSPointerFunctionsWeakMemory:弱引用成員

方法特性:
NSPointerFunctionsObjectPersonality:hash烈钞、isEqual泊碑、對象描述
NSPointerFunctionsOpaquePersonality:pointer 的 hash 、直接判等

內(nèi)存標識:
NSPointerFunctionsCopyIn 添加成員時進行 copy 操作

提供 compact 方法剔除 NULL 元素

NSPointerArray 可以存儲 NULL毯欣,作為補充馒过,它也提供了 compact 方法,用于剔除數(shù)組中為 NULL 的成員酗钞。但是 compact 函數(shù)有個已經(jīng)報備的 bug腹忽,每次 compact 之前需要添加一個 NULL,否則會 compact 失敗

弱引用測試代碼

NSPointerArray *pointerArray = [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsWeakMemory];
@autoreleasepool{
    NSObject *obj = [NSObject new];
    [pointerArray addPointer:(__bridge void *)obj];
    NSLog(@"NSPointerArray is: %p count: %@", [pointerArray pointerAtIndex:0], @(pointerArray.count));
    // 輸出 NSPointerArray is: 0x60000000e800 count: 1
}
NSLog(@"After Release NSPointerArray is: %p count: %@", [pointerArray pointerAtIndex:0], @(pointerArray.count));
// 輸出 After Release NSPointerArray is: 0x0 count: 1
    
// 每次 compact 之前需要添加 NULL砚作,規(guī)避系統(tǒng) Bug
[pointerArray addPointer:NULL];
    
[pointerArray compact];
    
NSLog(@"After Compact NSPointerArray count: %@", @(pointerArray.count));
// 輸出 After Compact NSPointerArray count: 0

- 2. NSHashTable

特性介紹

NSHashTable 是 NSSet 的通用版本窘奏,和 NSSet / NSMutableSet 不同的是,NSHashTable 具有下面這些特性:

  • 與 NSSet/NSMutableSet 相對應葫录,NSSet/NSMutableSet 強引用集合對象
  • NSHashTable 可以弱引用集合對象着裹,一旦對象沒人持有了,NSHashTable 中的值也會被移除
  • NSHashTable 是可變的米同,沒有不可變的版本
  • 除了存儲對象求冷,NSHashTable 也可以存儲任意指針,比如 void *

初始化參數(shù)

+ (NSHashTable<ObjectType> *)hashTableWithOptions:(NSPointerFunctionsOptions)options;

NSHashTableOptions 的取值如下:

  • NSHashTableStrongMemory: 默認值窍霞,強引用集合對象匠题,與 NSSet 一樣
  • NSHashTableWeakMemory: 弱引用集合對象
  • NSHashTableZeroingWeakMemory: 廢棄,請使用 NSHashTableWeakMemory
  • NSHashTableCopyIn: 在將對象添加到集合之前但金,會拷貝對象
  • NSHashTableObjectPointerPersonality: 使用 shifted pointer 來做 hash 檢測及確定兩個對象是否相等

弱引用測試代碼

NSHashTable *hashTable = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
@autoreleasepool {
    NSObject *obj = [NSObject new];
    [hashTable addObject:obj];
    NSLog(@"hashTable is: %@", hashTable);
    // hashTable is: NSHashTable {[3] <NSObject: 0x6000035e3f60>}
}
    
NSLog(@"hashTable is: %@", hashTable);
// hashTable is: NSHashTable {}

- 3. NSMapTable

特性介紹

NSMapTable 是 NSDictionary 的通用版本韭山,和 NSDictionary/NSMutableDictionary 不同的是,NSMapTable 具有下面這些特性:

  • 與 NSDictionary/NSMutableDictionary 相對應冷溃,NSDictionary/NSMutableDictionary 對 Key 拷貝钱磅,對 Value 強引用
  • key 和 value 的內(nèi)存管理方式可以分開,如:key 是強引用似枕,value 是弱引用
  • NSMapTable 可以弱引用 Key 和 Value盖淡,一旦 Key 或 Value 中的某一個沒人持有了,NSMapTable 中對應的項也會被移除
  • NSMapTable 是可變的凿歼,沒有不可變的版本
  • 除了存儲對象褪迟,NSMapTable 也可以存儲任意指針冗恨,比如 void *

總結起來一共有 4 種可能:

  • key 為 strong,value 為 strong
  • key 為 strong味赃,value 為 weak
  • key 為 weak掀抹,value 為 strong
  • key 為 weak,value 為 weak
    當用 weak 修飾 key 或 value 時心俗,有一方被釋放傲武,則該鍵值對移除

初始化參數(shù)

可以在初始化 NSMapTable 時指定 NSPointerFunctionsOptions 來分別確定對 Key 和 Value 的內(nèi)存引用

+ (NSMapTable<KeyType, ObjectType> *)mapTableWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions;

  • NSMapTableStrongMemory: 默認值,強引用 Key/Value
  • NSMapTableWeakMemory: 弱引用 Key/Value
  • NSHashTableZeroingWeakMemory: 廢棄城榛,請使用 NSMapTableWeakMemory
  • NSMapTableCopyIn: 在將對象添加到集合之前揪利,會拷貝對象
  • NSMapTableObjectPointerPersonality: 使用 shifted pointer 來做 hash 檢測及確定兩個對象是否相等

弱引用測試代碼

NSMapTable *mapTable = [NSMapTable weakToStrongObjectsMapTable];
@autoreleasepool {
    NSObject *key = [NSObject new];
    NSObject *value = [NSObject new];
    [mapTable setObject:value forKey:key];
    NSLog(@"mapTable is: %@", mapTable);
    // mapTable is: NSMapTable {<NSObject: 0x6000008df890> -> <NSObject: 0x6000008df870>}
}
    
NSLog(@"mapTable is: %@", mapTable);
// mapTable is: NSMapTable {}
// key 是 weak 引用,所以析構之后 NSMapTable 就會移除對應的項

參照

參考: 弱引用集合對象

[toc]

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狠持,一起剝皮案震驚了整個濱河市土童,隨后出現(xiàn)的幾起案子咒唆,更是在濱河造成了極大的恐慌济丘,老刑警劉巖缴淋,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異王污,居然都是意外死亡,警方通過查閱死者的電腦和手機楚午,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門昭齐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人矾柜,你說我怎么就攤上這事阱驾。” “怎么了怪蔑?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵里覆,是天一觀的道長。 經(jīng)常有香客問我缆瓣,道長喧枷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任弓坞,我火速辦了婚禮隧甚,結果婚禮上,老公的妹妹穿的比我還像新娘渡冻。我一直安慰自己戚扳,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布族吻。 她就那樣靜靜地躺著帽借,像睡著了一般珠增。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宜雀,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天切平,我揣著相機與錄音,去河邊找鬼辐董。 笑死悴品,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的简烘。 我是一名探鬼主播苔严,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼孤澎!你這毒婦竟也來了届氢?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤覆旭,失蹤者是張志新(化名)和其女友劉穎退子,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體型将,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡寂祥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了七兜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丸凭。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖腕铸,靈堂內(nèi)的尸體忽然破棺而出惜犀,到底是詐尸還是另有隱情,我是刑警寧澤狠裹,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布虽界,位于F島的核電站,受9級特大地震影響涛菠,放射性物質發(fā)生泄漏浓恳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一碗暗、第九天 我趴在偏房一處隱蔽的房頂上張望颈将。 院中可真熱鬧,春花似錦言疗、人聲如沸晴圾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽死姚。三九已至人乓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間都毒,已是汗流浹背色罚。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留账劲,地道東北人戳护。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像瀑焦,于是被迫代替她去往敵國和親腌且。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 基礎集合類是每一門語言的基礎榛瓮,下面我們一起來對OC的基礎集合類進行一個總結铺董。 NSArray NSArray作為一...
    Mr_Baymax閱讀 1,050評論 0 0
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,089評論 1 32
  • 關于鍵值編碼 鍵值編碼(KVC)是一種由NSKeyValueCoding非正式協(xié)議提供的機制,對象采用該機制來提供...
    漸z閱讀 904評論 0 0
  • 卷首語 歡迎來到 objc.io 第七期禀晓! 這個月精续,我們選擇了 Foundation 框架作為我們的主題。 Fou...
    評評分分閱讀 1,519評論 0 8
  • 級別: ★★☆☆☆標簽:「iOS 」「避免常見崩潰」「FBKVOController」「KVO」作者: WYW[...
    QiShare閱讀 3,034評論 2 26