NSSet and NSDictionary, along with NSArray are the workhorse collection classes of Foundation. Unlike other standard libraries, implementation details are hidden from developers, allowing them to write simple code and trust that it will be (reasonably) performant.

However, even the best abstractions break down; their underlying assumptions overturned. In these cases, developers either venture further down the abstraction, or, if available use a more general-purpose solution.

For NSSet and NSDictionary, the breaking assumption was in the memory behavior when storing objects in the collection. For NSSet, objects are a strongly referenced, as are NSDictionary values. Keys, on the other hand, are copied by NSDictionary. If a developer wanted to store a weak value, or use a non-<NSCopying>-conforming object as a key, they could be clever and use NSValue +valueWithNonretainedObject. Or, as of iOS 6 (and as far back as OS X Leopard), they could use NSHashTable or NSMapTable, the more general-case counterparts to NSSet or NSDictionary, respectively.

So without further ado, here's everything you need to know about two of the more obscure members of Foundation's collection classes:

NSHashTable

NSHashTable is a general-purpose analogue of NSSet. Contrasted with the behavior of NSSet / NSMutableSetNSHashTable has the following characteristics:

  • NSSet / NSMutableSet holds strong references to members, which are tested for hashing and equality using the methods hash and isEqual:.
  • NSHashTable is mutable, without an immutable counterpart.
  • NSHashTable can hold weak references to its members.
  • NSHashTable can copy members on input.
  • NSHashTable can contain arbitrary pointers, and use pointer identity for equality and hashing checks.

Usage

NSHashTable *hashTable = [NSHashTable hashTableWithOptions:NSPointerFunctionsCopyIn];
[hashTable addObject:@"foo"];
[hashTable addObject:@"bar"];
[hashTable addObject:@42];
[hashTable removeObject:@"bar"];
NSLog(@"Members: %@", [hashTable allObjects]);

NSHashTable objects are initialized with an option for any of the following behaviors. Deprecated enum values are due to NSHashTable being ported from Garbage-Collected OS X to ARC-ified iOS. Other values are aliased to options defined by NSPointerFunctions, which will be covered next week on NSHipster.

  • NSHashTableStrongMemory: Equal to NSPointerFunctionsStrongMemory. This is the default behavior, equivalent to NSSet member storage.
  • NSHashTableWeakMemory: Equal to NSPointerFunctionsWeakMemory. Uses weak read and write barriers. Using NSPointerFunctionsWeakMemory, object references will turn to NULL on last release.
  • NSHashTableZeroingWeakMemory: This option has been deprecated. Instead use the NSHashTableWeakMemory option.
  • NSHashTableCopyIn: Use the memory acquire function to allocate and copy items on input (see NSPointerFunction -acquireFunction). Equal to NSPointerFunctionsCopyIn.
  • NSHashTableObjectPointerPersonality: Use shifted pointer for the hash value and direct comparison to determine equality; use the description method for a description. Equal to NSPointerFunctionsObjectPointerPersonality.

NSMapTable

NSMapTable is a general-purpose analogue of NSDictionary. Contrasted with the behavior of NSDictionary / NSMutableDictionaryNSMapTable has the following characteristics:

  • NSDictionary / NSMutableDictionary copies keys, and holds strong references to values.
  • NSMapTable is mutable, without an immutable counterpart.
  • NSMapTable can hold keys and values with weak references, in such a way that entries are removed when either the key or value is deallocated.
  • NSMapTable can copy its values on input.
  • NSMapTable can contain arbitrary pointers, and use pointer identity for equality and hashing checks.

Usage

Instances where one might use NSMapTable include non-copyable keys and storing weak references to keyed delegates or another kind of weak object.

id delegate = ...;
NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory
valueOptions:NSMapTableWeakMemory];
[mapTable setObject:delegate forKey:@"foo"];
NSLog(@"Keys: %@", [[mapTable keyEnumerator] allObjects]);

NSMapTable objects are initialized with options specifying behavior for both keys and values, using the following enum values:

  • NSMapTableStrongMemory: Specifies a strong reference from the map table to its contents.
  • NSMapTableWeakMemory: Uses weak read and write barriers appropriate for ARC or GC. Using NSPointerFunctionsWeakMemory, object references will turn to NULL on last release. Equal to NSMapTableZeroingWeakMemory.
  • NSHashTableZeroingWeakMemory: This option has been superseded by the NSMapTableWeakMemory option.
  • NSMapTableCopyIn: Use the memory acquire function to allocate and copy items on input (see acquireFunction (see NSPointerFunction -acquireFunction). Equal to NSPointerFunctionsCopyIn.
  • NSMapTableObjectPointerPersonality: Use shifted pointer hash and direct equality, object description. Equal to NSPointerFunctionsObjectPointerPersonality.

Subscripting

NSMapTable doesn't implement object subscripting, but it can be trivially added in a category. NSDictionary's NSCopying requirement for keys belongs to NSDictionary alone:

@implementation NSMapTable (NSHipsterSubscripting)

- (id)objectForKeyedSubscript:(id)key
{
return [self objectForKey:key];
} - (void)setObject:(id)obj forKeyedSubscript:(id)key
{
[self setObject:obj forKey:key];
} @end

As always, it's important to remember that programming is not about being clever: always approach a problem from the highest viable level of abstraction. NSSet and NSDictionary are great classes. For 99% of problems, they are undoubtedly the correct tool for the job. If, however, your problem has any of the particular memory management constraints described above, then NSHashTable & NSMapTablemay be worth a look.

---------

作为delegate弱引用的集合再合适不过了。

转自:http://nshipster.com/nshashtable-and-nsmaptable/

[转][iOS]NSHash​Table & NSMap​Table的更多相关文章

  1. mysqldump:Couldn't execute 'show create table `tablename`': Table tablename' doesn't exist (1146)

    遇到了一个错误mysqldump: Couldn't execute 'show create table `CONCURRENCY_ERRORS`': Table INVOICE_OLD.CONCU ...

  2. ORA-01747: user.table.column, table.column 或列说明无效

    Oracle.DataAccess.Client.OracleException ORA-01747: user.table.column, table.column 或列说明无效 原因1: 查了一下 ...

  3. SQLServer temporary table and table variable

    Temporary tables are created in tempdb.  The name "temporary" is slightly misleading, for ...

  4. Oracle10g 回收站及彻底删除table : drop table xx purge

    drop后的表被放在回收站(user_recyclebin)里,而不是直接删除掉.这样,回收站里的表信息就可以被恢复,或彻底清除. 1.通过查询回收站user_recyclebin获取被删除的表信息, ...

  5. user.table.column, table.column 或列说明无效

    Oracle统计采用别名出错(user.table.column, table.column 或列说明无效) >>>>>>>>>>>& ...

  6. lua中打印所以类型功能实现table嵌套table

    lua中打印所以类型功能实现 本人測试 number.string.bool.nil.table嵌套table.userdata没问题 共享一下有什么问题请拍砖 代码例如以下 cclog = func ...

  7. 使用vue的v-for生成table , 给table加上序号

    现在有一个使用mybatis的分页插件生成的table,table中数据是通过vue获得的 , 前台显示使用<tr v-for="item in items"> 后台v ...

  8. 表优化 altering table OPTIMIZE TABLE `sta_addr_copy`

    表优化 altering table OPTIMIZE TABLE `sta_addr_copy` [总结] 1.实际测试的结果是,在state sqlaltering table OPTIMIZE ...

  9. MySQL check table/optimize table/analyze table/REPAIR TABLE

    MySQL check table/optimize table/analyze table/REPAIR TABLE 转自:https://www.cnblogs.com/datastack/p/3 ...

随机推荐

  1. 搭建LNAMP环境(二)- 源码安装Nginx1.10

    上一篇:搭建LNAMP环境(一)- 源码安装MySQL5.6 1.yum安装编译nginx需要的包 yum -y install pcre pcre-devel zlib zlib-devel ope ...

  2. Linux驱动开发——pr_fmt的用法

    作者:彭东林 邮箱:pengdonglin137@163.com 在阅读kernel代码的时候,总是看到有很多驱动都在第一行定义pr_fmt,闲来没事,分析了一下, 发现,确实挺方便的.下面记录分享一 ...

  3. Python(六)面向对象、异常处理、反射、单例模式

    本章内容: 创建类和对象 面向对象三大特性(封装.继承.多态) 类的成员(字段.方法.属性) 类成员的修饰符(公有.私有) 类的特殊成员 isinstance(obj, cls) & issu ...

  4. Gatekeeper Pattern 把关(守门人)模式

    Protect applications and services by using a dedicated host instance that acts as a broker between c ...

  5. JQuery Sizzle引擎源代码分析

    最近在拜读艾伦在慕课网上写的JQuery课程,感觉在国内对JQuery代码分析透彻的人没几个能比得过艾伦.有没有吹牛?是不是我说大话了? 什么是Sizzle引擎? 我们经常使用JQuery的选择器查询 ...

  6. 如果你也会C#,那不妨了解下F#(5):模块、与C#互相调用

    F# 项目 在之前的几篇文章介绍的代码都在交互窗口(fsi.exe)里运行,但平常开发的软件程序可能含有大类类型和函数定义,代码不可能都在一个文件里.下面我们来看VS里提供的F#项目模板. F#项目模 ...

  7. PyQt4入门学习笔记(二)

    之前第一篇介绍了pyqt4的大小,移动位置,消息提示.这次我们介绍菜单和工具栏 QtGui.QmainWindow这个类可以给我们提供一个创建带有状态栏.工具栏和菜单栏的标准的应用. 状态栏 状态栏是 ...

  8. oracle运算符

    单引号('): 在Oracle中,应该只运用单引号将文本和字符和日期括起来,不能运用引号(包括单双引号)将数字括起来. 双引号("): 在Oracle中,单双引号意思不同.双引号被用来将包含 ...

  9. Checkbox 模板和样式

    <Style TargetType="{x:Type CheckBox}"> <Setter Property="FontFamily" Va ...

  10. 在公有云AZURE上部署私有云AZUREPACK以及WEBSITE CLOUD(三)

    (三) 搭建Windows Azure Pack环境 1安装SQL SERVER 2012 服务器 为简单起见,本例直接使用了Azure提供的具有SQLServer的Win2012 Server镜像来 ...