NSHashTable & NSMapTable

1,744 阅读2分钟

NSHashTable & NSMapTable

比起平时常用的 NSArrayNSDictionaryNSSetNSHashTableNSMapTable更为少见一些。 下面二者做一个简单的介绍。

NSArray & NSSet & NSHashTable

1. NSArray 与 NSSet 的区别

其实NSSet我们平时也很少遇到,大部分时间使用NSArray已经足够,那么二者有什么区别呢?

  1. 互异性:集合内的元素是不重复的。
  2. 无序性:NSSet在内存中存储方式是不连续的,而NSArray在内存中存储位置是连续的。
  3. 确定性:NSSet对元素的查找效率是比NSArray高的,因为它主要使用的是hash算法。查找时间稳定。

综上所述:可知NSSet适用于 不关心集合内元素的顺序,而是需要查找元素是否在集合中,且对查找的性能有要求的情况。在这种情况下,可以用NSSet代替NSArray来存储数据。同样的,Set也有一个可变类型的子类NSMutableSet

2. NSSet 与 NSHashTable 的区别

NSHashTable是一种类似NSSet一样的集合,但是它可用的内存语义范围更广,能够对持有对象以弱引用的方式存储。NSArrayNSSet对所持有的元素都是强持有(强引用),当我们需要对持有的元素进行弱引用时,便可以考虑使用NSHashTable

@interface NSHashTable<__covariant ObjectType> : NSObject

在初始化hashTable时,需要设置hashTable的options,有以下两种初始化方法。

- (**instancetype**)initWithOptions:(NSPointerFunctionsOptions)options capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER;
- (**instancetype**)initWithPointerFunctions:(NSPointerFunctions *)functions capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER;

在第一种初始化方法中,直接选择了由系统提供的几种hashTable的options,类型为NSPointerFunctionsOptions,内容如下。

**typedef** NS_OPTIONS(NSUInteger, NSPointerFunctionsOptions) {

    // Memory options are mutually exclusive
    // default is strong
    
    NSPointerFunctionsStrongMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (0UL << 0),       // use strong write-barrier to backing store; use GC memory on copyIn
    NSPointerFunctionsZeroingWeakMemory API_DEPRECATED("GC no longer supported", macos(10.5, 10.8)) API_UNAVAILABLE(ios, watchos, tvos) = (1UL << 0),  // deprecated; uses GC weak read and write barriers, and dangling pointer behavior otherwise
    NSPointerFunctionsOpaqueMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (2UL << 0),
    NSPointerFunctionsMallocMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (3UL << 0),       // free() will be called on removal, calloc on copyIn
    NSPointerFunctionsMachVirtualMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (4UL << 0),
    NSPointerFunctionsWeakMemory API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0)) = (5UL << 0),         // uses weak read and write barriers appropriate for ARC

    // Personalities are mutually exclusive
    // default is object.  As a special case, 'strong' memory used for Objects will do retain/release under non-GC

    NSPointerFunctionsObjectPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (0UL << 8),         // use -hash and -isEqual, object description
    NSPointerFunctionsOpaquePersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (1UL << 8),         // use shifted pointer hash and direct equality
    NSPointerFunctionsObjectPointerPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (2UL << 8),  // use shifted pointer hash and direct equality, object description
    NSPointerFunctionsCStringPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (3UL << 8),        // use a string hash and strcmp, description assumes UTF-8 contents; recommended for UTF-8 (or ASCII, which is a subset) only cstrings
    NSPointerFunctionsStructPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (4UL << 8),         // use a memory hash and memcmp (using size function you must set)
    NSPointerFunctionsIntegerPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (5UL << 8),        // use unshifted value as hash & equality
    NSPointerFunctionsCopyIn API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (1UL << 16),      // the memory acquire function will be asked to allocate and copy items on input

};

默认是NSPointerFunctionsStrongMemory,即内存强引用,效果和NSSet类似,会造成对持有元素的强引用。而在其后的NSPointerFunctionsWeakMemory,则是与之对应的弱引用。

NSDictionary & NSMapTable

1. NSDictionary 和 NSMapTable 的区别

与上面的 NSSet & NSHashTable 相同的,NSDictionaryNSMapTable 也是在对其所持有的元素的引用状态上有区别。并且,因为每个map对象有 <key, value> 两个元素,所以mapTable的options也更多,key和value都可以选择 强引用or弱引用。

初始化方法如下。

- (**instancetype**)initWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER;
- (**instancetype**)initWithKeyPointerFunctions:(NSPointerFunctions *)keyFunctions valuePointerFunctions:(NSPointerFunctions *)valueFunctions capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER;

可以看到,第一个初始化方法中,我们可以分别设置 keyOptionsvalueOptions。内存语义的类型选择与hashTable相同。