NSHashMap / NSHashTable / NSPointerArray

0x01 場(chǎng)景分析

需要?jiǎng)?chuàng)建一個(gè)集合,但是又不想讓集合引用內(nèi)部變量,這樣就可以在內(nèi)部變量被銷(xiāo)毀是,不會(huì)因?yàn)榧弦昧诉@個(gè)變量而導(dǎo)致無(wú)法被銷(xiāo)毀。
如果我們使用NSMutableSet來(lái)進(jìn)行操作,就會(huì)因?yàn)?code>NSMutableSet對(duì)內(nèi)部的元素多一個(gè)強(qiáng)引用導(dǎo)致無(wú)法釋放。那么有沒(méi)有其他集合方案可以讓我們自由控制內(nèi)存引用關(guān)系呢。

iOS6.0是就已經(jīng)提供了支持,目的是為了拓展集合對(duì)內(nèi)部元素的引用關(guān)系。
NSHashTable 相當(dāng)于NSMutableSet,但是可以對(duì)其內(nèi)部的引用關(guān)系做額外設(shè)置,不像NSMutableSet只是用來(lái)做強(qiáng)引用。


0x02 NSHashTable

NSHashTable允許我們自定義集合對(duì)其內(nèi)部元素的內(nèi)存引用方案。更廣泛意義的NSSet,區(qū)別于NSSet/NSMUtableSet, NSHashTable有以下特性

  • 可變
  • 可以持有weak類(lèi)型的成員變量
  • 可以再添加成員變量的時(shí)候復(fù)制成員
  • 可以任意的存儲(chǔ)指針,并且利用指針的唯一性來(lái)進(jìn)行對(duì)比和重復(fù)檢查。

可行的方案

// 對(duì)成員變量進(jìn)行強(qiáng)引用
NSHashTableStrongMemory /   NSPointerFunctionsStrongMemory

// 在ARC下使用弱引用方式進(jìn)行讀寫(xiě),在最后一次釋放后,引用對(duì)象將會(huì)被置為NULL
NSHashTableWeakMemory   /   NSPointerFunctionsWeakMemory

// 在對(duì)象被加入到集合中前進(jìn)行復(fù)制
NSHashTableCopyIn   /   NSPointerFunctionsCopyIn

// 用指針來(lái)等同替代實(shí)際的值,當(dāng)打印這個(gè)指針時(shí),相當(dāng)于調(diào)用了description方法
NSHashTableObjectPointerPersonality / NSPointerFunctionsObjectPointerPersonality
// 存儲(chǔ)時(shí),對(duì)要存儲(chǔ)的對(duì)象A進(jìn)行弱引用,當(dāng)A被釋放時(shí),會(huì)自動(dòng)在table中移除
NSHashTable *table = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
// NSHashTable *table = [NSHashTable weakObjectsHashTable]; 功能一樣

Aobj *a = [Aobj new];
[table.addObject:a];

// 強(qiáng)引用,與NSMUtableSet功能一樣
NSHashTable *table = [NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory];
Aobj *a = [Aobj new];
[table.addObject:a];

0x03 NSMapTable

NSMapTable是更廣泛意義的NSMutableDictionary,我們可以自定義內(nèi)存管理方案。

NSDictionary/NSMutableDictionary會(huì)賦值keys并且通過(guò)強(qiáng)引用value來(lái)實(shí)現(xiàn)存儲(chǔ)。

NSMapTableNSDictionary/NSMUtableDictionary相比具有以下特性:

  • 可變
  • 可以通過(guò)弱引用來(lái)持有keysvalues,所以當(dāng)key或者valuedeallocated的時(shí)候,所存儲(chǔ)的實(shí)體也會(huì)被移除。
  • 可以在添加value的時(shí)候?qū)?code>value進(jìn)行復(fù)制
  • 可以任意的存儲(chǔ)指針 ,并且利用指針的唯一性來(lái)進(jìn)行對(duì)比和重復(fù)性檢測(cè)。
    可行性方案:
// 對(duì)成員變量進(jìn)行強(qiáng)引用
NSMapTableStrongMemory / NSPointerFunctionsStrongMemory

// 對(duì)成員變量進(jìn)行弱引用
NSMapTableWeakMemory

// 在對(duì)象被加入到字典中前進(jìn)行復(fù)制
NSMapTableCopyIn    / NSPointerFunctionsCopyIn.

// 用指針來(lái)等同替代實(shí)際的值
NSMapTableObjectPointerPersonality / NSPointerFunctionsObjectPointerPersonality
    NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableCopyIn                                              valueOptions:NSMapTableCopyIn];     // value使用copyIn,Person需要實(shí)現(xiàn)NSCopying協(xié)議
        {
            Person *p = [Person new];
            [mapTable setObject:p forKey:@"foo"];
        }
        NSLog(@"Keys: %@", [[mapTable keyEnumerator] allObjects]);
        NSLog(@"values:%@",[mapTable objectForKey:@"foo"]);
        

注意:NSMapTable不能繼承subscripting
因?yàn)橄聵?biāo)訪(fǎng)問(wèn)需要一個(gè)id作為key,對(duì)于NSMapTable來(lái)說(shuō),這不是強(qiáng)制的。


0x04 NSPointArray

一個(gè)稀疏數(shù)組,與NSMutableArray相似,但可以存儲(chǔ)NULL值。如果存在NULL索引會(huì)發(fā)生改變。
在性能方面,NSPointerArray非常慢,所以當(dāng)你打算在一個(gè)很大的數(shù)據(jù)集合上使用它時(shí)一定要三思。

可行性方案:

// 對(duì)成員變量進(jìn)行強(qiáng)引用
NSPointerFunctionsStrongMemory

// 對(duì)成員變量進(jìn)行弱引用
NSPointerFunctionsWeakMemory

// 在加入集合前執(zhí)行copy
NSPointerFunctionsCopyIn

// 使用對(duì)象的hash和isEqual:(默認(rèn))。
NSPointerFunctionsObjectPersonality

// 對(duì)于isEqual:和hash使用直接的指針比較。
NSPointerFunctionsObjectPointerPersonality

NSPointerArray *ptrArray  = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsWeakMemory];
// NSPointerArray *ptrArray  = [NSPointerArray weakObjectsPointerArray];    效果一樣
        for (int i = 0; i < 3; i ++)
        {
            Person *p = [Person new];
            [ptrArray addPointer:(__bridge void *)p];
        }
        void *a = (__bridge void *)@10;
        // void *a = 10;    會(huì)crash,原因就是在
        [ptrArray addPointer:a];
        NSLog(@"---%@",ptrArray.allObjects);

0x05 NSPointerFunctionsOptions

是一個(gè)option,主要分為三大類(lèi):

內(nèi)存管理語(yǔ)義

// 缺省值,在 CG 和 MRC 下強(qiáng)引用成員
NSPointerFunctionsStrongMemory

// 在指針去除時(shí)不做任何動(dòng)作
NSPointerFunctionsOpaqueMemory 

// 用于 Mach 的虛擬內(nèi)存管理
NSPointerFunctionsMallocMemory 與 NSPointerFunctionsMachVirtualMemory

// 在 CG 或者 ARC 下,弱引用成員
NSPointerFunctionsWeakMemory

特性

對(duì)象處理選項(xiàng)即如何進(jìn)行哈希算法,判定同等性,描述

// 使用NSObject的hash, isEqual, description,默認(rèn)
NSPointerFunctionsObjectPersonality

//使用偏移后指針,進(jìn)行hash和直接比較同等性
NSPointerFunctionsOpaquePersonality

// 和上一個(gè)相同,多了description方法
NSPointerFunctionsObjectPointerPersonality

// 使用C字符串的hash、strcmp 函數(shù)、UTF-8 編碼方式的描述
NSPointerFunctionsCStringPersonality

// 使用內(nèi)存的hash、memcmp
NSPointerFunctionsStructPersonality

// 使用偏移量作為hash和等同性判斷
NSPointerFunctionsIntegerPersonality

內(nèi)存標(biāo)識(shí)

// 根據(jù)第二類(lèi)的選擇,來(lái)具體處理
// 如果是 NSPointerFunctionsObjectPersonality,則根據(jù) NSCopying 來(lái)拷貝。
NSPointerFunctionsCopyIn

注意: 每種類(lèi)別的選項(xiàng)只能選擇一個(gè)

所以在使用時(shí),可以多個(gè)組合。比如:需要強(qiáng)引用成員,使用對(duì)象方式對(duì)比,并且add時(shí)copy對(duì)象

NSPointerFunctionsOptions *options = NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality | NSPointerFunctionsCopyIn;

0x06 總結(jié)

正常情況下我們使用NSArray/NSMutableArray,NSSet/NSMutableSetNSDictionary/NSMutableDictionary就可以達(dá)到90%以上的需求。如果自定義程度更高,我們就可以去考慮使用NSHashTable,NSMapTable,NSPointerArray來(lái)解決問(wèn)題。


參考:
https://blog.csdn.net/u012597860/article/details/51240430
https://www.cnblogs.com/zhaoguowen/p/4273237.html
https://www.cnblogs.com/lxlx1798/p/6651949.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容