[iOS]NSHashTable和NSMapTable用法


[iOS]NSHashTable和NSMapTable用法 - 簡(jiǎn)書(shū)

一個(gè)項(xiàng)目中的需求

在iOS項(xiàng)目開(kāi)發(fā)過(guò)程中,我們經(jīng)常會(huì)使用到NSSet、NSArray、NSDictionary三個(gè)類(lèi),它們?yōu)槲覀冊(cè)O(shè)計(jì)較友好的數(shù)據(jù)結(jié)構(gòu)時(shí)提供了很方便的方法

先準(zhǔn)備本文中將要使用的對(duì)象:

#import@interfaceHHHuman:NSObject@property(nonatomic,strong)NSString*name;+ (instancetype) humanWithName:(NSString*)n;@end@implementationHHHuman+ (instancetype) humanWithName:(NSString*)n{? ? HHHuman *human = [[HHHuman alloc] init];? ? human.name= n;return[human autorelease];}- (NSString*)description{return[NSStringstringWithFormat:@"%@'s retainCount is %lu",self.name,[selfretainCount]];}- (void)dealloc{self.name=nil;? ? [superdealloc];}@end

在程序開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)用到諸如此類(lèi)的Model對(duì)象.

用法呢也大致會(huì)有如下幾種方式:

1.通過(guò)有序的數(shù)列進(jìn)行存儲(chǔ),數(shù)組NSArray;

HHHuman *human_1 = [HHHuman humanWithName:@"lilei"];? ? HHHuman *human_2 = [HHHuman humanWithName:@"hanmeimei"];? ? HHHuman *human_3 = [HHHuman humanWithName:@"lewis"];? ? HHHuman *human_4 = [HHHuman humanWithName:@"xiaohao"];? ? HHHuman *human_5 = [HHHuman humanWithName:@"beijing"];idlist = @[human_1,human_2,human_3,human_4,human_5];NSLog(@"%@",list);

輸出的結(jié)果如下:

("lilei's retainCount is 2","hanmeimei's retainCount is 2","lewis's retainCount is 2","xiaohao's retainCount is 2","beijing's retainCount is 2")

2.通過(guò)統(tǒng)一的關(guān)鍵字進(jìn)行存儲(chǔ),字典N(xiāo)SDictionary;

HHHuman *human_1 = [HHHuman humanWithName:@"lilei"];? ? HHHuman *human_2 = [HHHuman humanWithName:@"hanmeimei"];? ? HHHuman *human_3 = [HHHuman humanWithName:@"lewis"];? ? HHHuman *human_4 = [HHHuman humanWithName:@"xiaohao"];? ? HHHuman *human_5 = [HHHuman humanWithName:@"beijing"];iddic = @{@"excellent":human_1};//同樣在控制臺(tái)輸出上文字典,用來(lái)查看每個(gè)對(duì)象的保留值NSLog(@"%@",list);

輸出的結(jié)果如下:

("lilei's retainCount is 3","hanmeimei's retainCount is 3","lewis's retainCount is 2","xiaohao's retainCount is 2","beijing's retainCount is 2")

通過(guò)上述兩個(gè)例子我們能夠發(fā)現(xiàn)一個(gè)問(wèn)題,即將對(duì)象添加到容器時(shí),會(huì)對(duì)該對(duì)象的引用技術(shù)+1

這樣就會(huì)有可能發(fā)生循環(huán)持有的問(wèn)題,例如如下代碼:

@interfaceHHHuman:NSObject@property(nonatomic,strong)NSString*name;@property(nonatomic,strong)NSMutableArray*family;+ (instancetype) humanWithName:(NSString*)n;@end@implementationHHHuman+ (instancetype) humanWithName:(NSString*)n{? ? HHHuman *human = [[HHHuman alloc] init];? ? human.name= n;? ? human.family= [[NSMutableArrayalloc] init];? ? [human.familyaddObject:human];return[human autorelease];}- (NSString*)description{return[NSStringstringWithFormat:@"%@'s retainCount is %lu",self.name,[selfretainCount]];}- (void)dealloc{self.name=nil;self.family=nil;? ? [superdealloc];}@end

在以上代碼中,一個(gè)human的實(shí)例對(duì)象中包含一個(gè)strong修飾的family屬性,但是在family屬性中,又添加了human自身對(duì)象,這樣會(huì)造成循環(huán)持有的問(wèn)題,而導(dǎo)致內(nèi)存泄漏。

但是項(xiàng)目需求又要求我們?cè)谠揗odel對(duì)象中完成如此代碼,我們不得已會(huì)多創(chuàng)建一個(gè)類(lèi)HHHumanRelationShip,如下所示:

#import@interfaceHHHuman:NSObject@property(nonatomic,strong)NSString*name;+ (instancetype) humanWithName:(NSString*)n;@end@implementationHHHuman+ (instancetype) humanWithName:(NSString*)n{? ? HHHuman *human = [[HHHuman alloc] init];? ? human.name= n;return[human autorelease];}- (NSString*)description{return[NSStringstringWithFormat:@"%@'s retainCount is %lu",self.name,[selfretainCount]];}- (void)dealloc{self.name=nil;? ? [superdealloc];}@end@interfaceHHHumanRelationShip:NSObject@property(nonatomic,strong) HHHuman *human;@property(nonatomic,strong)NSArray*family;+ (instancetype)relationShipWithHuman:(HHHuman *)human family:(NSArray*)members;@end@implementationHHHumanRelationShip+ (instancetype)relationShipWithHuman:(HHHuman *)human family:(NSArray*)members{? ? HHHumanRelationShip *rs = [[HHHumanRelationShip alloc] init];? ? rs.human= human;? ? rs.family= members;return[rs autorelease];}- (NSString*)description{return[NSStringstringWithFormat:@"%@'s family's member is %@",self.human,self.family];}- (void)dealloc{self.human=nil;self.family=nil;? ? [superdealloc];}@endintmain(intargc,constchar* argv[]){? ? HHHuman *human_0 = [HHHuman humanWithName:@"parent"];? ? HHHuman *human_1 = [HHHuman humanWithName:@"lilei"];? ? HHHuman *human_2 = [HHHuman humanWithName:@"hanmeimei"];? ? HHHuman *human_3 = [HHHuman humanWithName:@"lewis"];? ? HHHuman *human_4 = [HHHuman humanWithName:@"xiaohao"];? ? HHHuman *human_5 = [HHHuman humanWithName:@"beijing"];idlist = @[human_1,human_2,human_3,human_4,human_5];? ? HHHumanRelationShip *relationShip = [HHHumanRelationShip relationShipWithHuman:human_0 family:list];NSLog(@"%@",relationShip);return0;}

NSHashTable

很明顯,大家能夠看到這樣造成了程序代碼的臃腫

根據(jù)上述需求和功能,在iOS6之后,Objective-C Foundation框架中添加了兩個(gè)類(lèi)分別是NSHashTable和NSMapTable

NSHashTable

構(gòu)造函數(shù)

- (instancetype)initWithOptions:(NSPointerFunctionsOptions)options capacity:(NSUInteger)initialCapacity

- (instancetype)initWithPointerFunctions:(NSPointerFunctions *)functions capacity:(NSUInteger)initialCapacity

+ (NSHashTable *)hashTableWithOptions:(NSPointerFunctionsOptions)options;

+ (id)hashTableWithWeakObjects;

+ (NSHashTable *)weakObjectsHashTable;

在創(chuàng)建NSHashTable對(duì)象時(shí),會(huì)傳NSPointerFunctionsOptions參數(shù),列舉如下:

NSHashTableStrongMemory

將HashTable容器內(nèi)的對(duì)象引用計(jì)數(shù)+1一次

NSHashTableZeroingWeakMemory

在OSX 10.8之后已經(jīng)廢棄

NSHashTableCopyIn

將添加到容器的對(duì)象通過(guò)NSCopying中的方法,復(fù)制一個(gè)新的對(duì)象存入HashTable容器

NSHashTableObjectPointerPersonality

使用移位指針(shifted pointer)來(lái)做hash檢測(cè)及確定兩個(gè)對(duì)象是否相等;

NSHashTableWeakMemory

不會(huì)修改HashTable容器內(nèi)對(duì)象元素的引用計(jì)數(shù),并且對(duì)象釋放后,會(huì)被自動(dòng)移除

對(duì)于我們來(lái)說(shuō),NSHashTable吸引力比較大的即NSHashTableWeakMemory特性.

使用一段代碼來(lái)展示功能:

#import@interfaceHHHuman:NSObject@property(nonatomic,strong)NSString*name;@property(nonatomic,strong)NSHashTable*family;+ (instancetype) humanWithName:(NSString*)n;@end@implementationHHHuman+ (instancetype) humanWithName:(NSString*)n{? ? HHHuman *human = [[HHHuman alloc] init];? ? human.name= n;? ? human.family= [NSHashTablehashTableWithOptions:NSHashTableWeakMemory];? ? [human.familyaddObject:human];return[human autorelease];}- (NSString*)description{return[NSStringstringWithFormat:@"%@'s retainCount is %lu",self.name,[selfretainCount]];}- (void)dealloc{self.name=nil;self.family=nil;? ? [superdealloc];}@endintmain(intargc,constchar* argv[]){//創(chuàng)建一個(gè)NSHashTableWeakMemory特性的HashTable對(duì)象NSHashTable*hash_tab = [NSHashTablehashTableWithOptions:NSHashTableWeakMemory];//創(chuàng)建自動(dòng)釋放池對(duì)象NSAutoreleasePool*pool = [[NSAutoreleasePoolalloc] init];//通過(guò)便利構(gòu)造器獲取一個(gè)name屬性是lewis的human對(duì)象HHHuman *human = [HHHuman humanWithName:@"lewis"];//將該對(duì)象添加到HashTable容器中[hash_tab addObject:human];//釋放之前打印humanNSLog(@"before pool:%@",human);//將自動(dòng)釋放池釋放掉[pool drain];//釋放之后打印hash_tabNSLog(@"after pool:%@",hash_tab);return0;}

在控制臺(tái)輸出的結(jié)果如下

before pool:lewis'sretainCount is1after pool:NSHashTable{}

我們可以看到,當(dāng)pool對(duì)象釋放時(shí),human的引用計(jì)數(shù)會(huì)執(zhí)行一次-1,human對(duì)象在內(nèi)存中就會(huì)自動(dòng)釋放,并且相應(yīng)的hash_tab對(duì)象中的對(duì)象也會(huì)被自動(dòng)移除.

而我們?cè)趧?chuàng)建hash_tab時(shí)使用的是NSHashTableStrongMemory特性話(huà),那么控制臺(tái)輸出的結(jié)果如下:

before pool:lewis'sretainCount is2after pool:NSHashTable{[13] lewis'sretainCount is1}

有了NSHashTable就可以完成我們文章一開(kāi)始的需求了.

#import@interfaceHHHuman:NSObject@property(nonatomic,strong)NSString*name;@property(nonatomic,strong)NSHashTable*family;+ (instancetype) humanWithName:(NSString*)n;@end@implementationHHHuman+ (instancetype) humanWithName:(NSString*)n{? ? HHHuman *human = [[HHHuman alloc] init];? ? human.name= n;? ? human.family= [NSHashTablehashTableWithOptions:NSHashTableWeakMemory];? ? [human.familyaddObject:human];return[human autorelease];}- (NSString*)description{return[NSStringstringWithFormat:@"%@'s retainCount is %lu",self.name,[selfretainCount]];}- (void)dealloc{self.name=nil;self.family=nil;? ? [superdealloc];}@end

NSHashTable可以使用的函數(shù)

typedefstruct{NSUInteger_pi;NSUInteger_si;void*_bs;}NSHashEnumerator;FOUNDATION_EXPORTvoidNSFreeHashTable(NSHashTable*table);FOUNDATION_EXPORTvoidNSResetHashTable(NSHashTable*table);FOUNDATION_EXPORTBOOLNSCompareHashTables(NSHashTable*table1,NSHashTable*table2);FOUNDATION_EXPORTNSHashTable*NSCopyHashTableWithZone(NSHashTable*table,NSZone*zone);FOUNDATION_EXPORTvoid*NSHashGet(NSHashTable*table,constvoid*pointer);FOUNDATION_EXPORTvoidNSHashInsert(NSHashTable*table,constvoid*pointer);FOUNDATION_EXPORTvoidNSHashInsertKnownAbsent(NSHashTable*table,constvoid*pointer);FOUNDATION_EXPORTvoid*NSHashInsertIfAbsent(NSHashTable*table,constvoid*pointer);FOUNDATION_EXPORTvoidNSHashRemove(NSHashTable*table,constvoid*pointer);FOUNDATION_EXPORTNSHashEnumeratorNSEnumerateHashTable(NSHashTable*table);FOUNDATION_EXPORTvoid*NSNextHashEnumeratorItem(NSHashEnumerator*enumerator);FOUNDATION_EXPORTvoidNSEndHashTableEnumeration(NSHashEnumerator*enumerator);FOUNDATION_EXPORTNSUIntegerNSCountHashTable(NSHashTable*table);FOUNDATION_EXPORTNSString*NSStringFromHashTable(NSHashTable*table);FOUNDATION_EXPORTNSArray*NSAllHashTableObjects(NSHashTable*table);

NSMapTable

NSMapTable

構(gòu)造函數(shù)

- (instancetype)initWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions capacity:(NSUInteger)initialCapacity;

- (instancetype)initWithKeyPointerFunctions:(NSPointerFunctions *)keyFunctions valuePointerFunctions:(NSPointerFunctions *)valueFunctions capacity:(NSUInteger)initialCapacity;

+ (NSMapTable *)mapTableWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions;

+ (NSMapTable *)strongToStrongObjectsMapTable;

+ (NSMapTable *)weakToStrongObjectsMapTable;

+ (NSMapTable *)strongToWeakObjectsMapTable;

+ (NSMapTable *)weakToWeakObjectsMapTable;

NSMapTable對(duì)象類(lèi)似與NSDictionary的數(shù)據(jù)結(jié)構(gòu),但是NSMapTable功能比NSDictionary對(duì)象要多的功能就是可以設(shè)置key和value的NSPointerFunctionsOptions特性!其他的用法與NSDictionary相同.

NSMapTable可以使用的函數(shù)

FOUNDATION_EXPORTvoidNSFreeMapTable(NSMapTable*table);FOUNDATION_EXPORTvoidNSResetMapTable(NSMapTable*table);FOUNDATION_EXPORTBOOLNSCompareMapTables(NSMapTable*table1,NSMapTable*table2);FOUNDATION_EXPORTNSMapTable*NSCopyMapTableWithZone(NSMapTable*table,NSZone*zone);FOUNDATION_EXPORTBOOLNSMapMember(NSMapTable*table,constvoid*key,void**originalKey,void**value);FOUNDATION_EXPORTvoid*NSMapGet(NSMapTable*table,constvoid*key);FOUNDATION_EXPORTvoidNSMapInsert(NSMapTable*table,constvoid*key,constvoid*value);FOUNDATION_EXPORTvoidNSMapInsertKnownAbsent(NSMapTable*table,constvoid*key,constvoid*value);FOUNDATION_EXPORTvoid*NSMapInsertIfAbsent(NSMapTable*table,constvoid*key,constvoid*value);FOUNDATION_EXPORTvoidNSMapRemove(NSMapTable*table,constvoid*key);FOUNDATION_EXPORTNSMapEnumeratorNSEnumerateMapTable(NSMapTable*table);FOUNDATION_EXPORTBOOLNSNextMapEnumeratorPair(NSMapEnumerator*enumerator,void**key,void**value);FOUNDATION_EXPORTvoidNSEndMapTableEnumeration(NSMapEnumerator*enumerator);FOUNDATION_EXPORTNSUIntegerNSCountMapTable(NSMapTable*table);FOUNDATION_EXPORTNSString*NSStringFromMapTable(NSMapTable*table);FOUNDATION_EXPORTNSArray*NSAllMapTableKeys(NSMapTable*table);FOUNDATION_EXPORTNSArray*NSAllMapTableValues(NSMapTable*table);

文/肖浩唄(簡(jiǎn)書(shū)作者)

原文鏈接:http://www.itdecent.cn/p/de71385930ba

著作權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),并標(biāo)注“簡(jiǎn)書(shū)作者”。

最后編輯于
?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

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