ios中常见容器
- array:存储一组有序的值
- set:存储一组无序的值
- dictionary:存储一组无序的key-value映射
其他高阶
- NSCountedSet
- NSIndexSet && NSMutableIndexSet
- NSOrderedSet && NSMutableOrderedSet
- NSPointerArray
- NSMapTable
- NSHashTable
- NSCache
- NSArray
数组在内存上是连续存储空间,可以通过index下标获取数组元素。 - NSSet
集合在内存上是不连续的,相同元素只能存在一个,一种哈希表,运用散列算法,查找集合中的元素比数组速度更快,但是它没有顺序。 - NSDictionary
字典在内存上是不连续的,通过key-value映射。一种哈希表,通过哈希算法得到key的哈希值去表中查对应的value,它没有顺序。
NSCountedSet
是无序集合,可以添加、移除元素,判断元素是否存在及保证元素唯一性。还有两个主要特点:
- 一个元素可以多次添加
- 可以获取元素数量
使用场景如购物车同一个产品购买多个,使用NSCountedSet想对字典会更方便
NSIndexSet && NSMutableIndexSet
是包含不重复整数的容器类型,使得索引访问具备批量执行的能力。
NSMutableIndexSet *indexs = [[NSMutableIndexSet alloc]init];
[indexs addIndex:1];
[indexs addIndex:3];
NSArray *arr = @[@"1",@"2",@"3",@"4",@"5",@"6"];
NSLog(@"items=%@",[arr objectsAtIndexes:indexs]);
//log items=(
2,
4
)
NSMutableIndexSet *indexs = [[NSMutableIndexSet alloc]init];
[indexs addIndexesInRange:NSMakeRange(0, 2)];
[indexs addIndexesInRange:NSMakeRange(4, 1)];
NSArray *arr = @[@"1",@"2",@"3",@"4",@"5",@"6"];
NSLog(@"items=%@",[arr objectsAtIndexes:indexs]);
//log items=(
1,
2,
5
)
NSOrderedSet && NSMutableOrderedSet
是有序 Set,比 传统 NSSet 增加了索引功能,且能够保持元素的插入顺序。
NSString *str1 = @"str1";
NSString *str2 = @"str2";
NSString *str3 = @"str3";
NSString *str4 = @"str4";
NSOrderedSet *set = [[NSOrderedSet alloc] initWithObjects:str1,str2,str3,str4, nil];
NSString *res1 = [set objectAtIndex:1];//
NSInteger index = [set indexOfObject:str4];//
NSString *res2 = set[2];//支持下标取值
NSLog(@"res1=%@ index=%d res2=%@",res1,index,res2);
//log res1=str2 index=3 res2=str3
注:在与NSArray的性能上比较
NSPointerArray
是 NSMutableArray 的高阶类型,比 NSMutableArray 具备更广泛的内存管理能力,具体如下:
- 和传统 NSArray 一样,用于有序的插入或移除;
- 与传统 NSArray 不同的是,可以存储 NULL,且 NULL 参与 count 的计算;
- 与传统 NSArray 不同的是,count 可以被设置,如果设置较大的 count 则使用 NULL 占位;
- 可以使用 weak 或 unsafe_unretained 来修饰成员;
- 可以修改对象的判等方式;
- 可以使对象加入时进行拷贝;
- 成员可以是所有指针类型,不仅限于 OC 对象;
NSObject *obj = [[NSObject alloc] init];
NSPointerArray *pointer1 = [NSPointerArray weakObjectsPointerArray];
[pointer1 addPointer:(__bridge void *)(obj)];//obj 引用计数不会变化 添加时是weak引用
NSPointerArray *pointer2 = [NSPointerArray strongObjectsPointerArray];
[pointer2 addPointer:(__bridge void *)obj];//obj 引用计数+1 添加时是strong引用
//注:obj 被释放后,pointerArray.count 依然是1,这是因为 NULL 也会参与占位。调用 compact 方法将清空所有的 NULL 占位。
通过函数 + pointerArrayWithOptions:指定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
};
内存相关
- NSPointerFunctionsOptions 是一个选项,不同于枚举,选项类型是可以叠加的。这些选项可以分为内存管理、个性判定、拷贝偏好三大类:
- NSPointerFunctionsWeakMemory: 弱引用,不增加引用计数。元素被释放后变成 NULL,但 count 保持不变。调用 compact 方法后将删除所有 NULL 元素并重新调整大小。对应 ARC 的weak。
- NSPointerFunctionsStrongMemory:强引用,引用计数+1。对应 ARC 的 strong。
- NSPointerFunctionsOpaqueMemory:不增加引用计数,也不创建弱引用,元素释放后变野指针。对应 ARC 的 unsafe_unretained。
- NSPointerFunctionsMallocMemory:移除元素时调用 free() 进行释放,添加时调用 calloc()。不同于上面三种,这种方式适用于元素为普通指针类型的情况。
- NSPointerFunctionsMachVirtualMemory:用于 Mach 的虚拟内存管理。
个性判定
- 相等性判定(即判等)。传统容器都是使用元素的 -isEqual 进行相等性判定。当对 NSArray 调用 indexOfObject 方法时,数组会遍历内部元素,对每个遍历到的元素与输入元素进行 isEqual 对比,直到碰到第一个判定成功(即 isEqual 返回 YES)的元素并返回其索引;若所有元素均判定失败则返回 NSNotFound。
- 哈希值判定。如使用对象的 Hash 方法是一种哈希值判定方式。常见的 NSSet、NSDictionary 都是使用元素的 Hash 方法获取哈希值,从而决定其索引位置。
- 描述值判定。如使用对象的 Description 方法是一种描述值判定方式。
拷贝偏好
- NSPointerFunctionsCopyIn: 添加元素时,实际添加的是元素的拷贝。
传统数组就相当于一个特殊的 NSPointerArray,把它的 options 设成这样:NSPointerFunctionsStrongMemory| NSPointerFunctionsObjectPersonality 即个性判定为 OC 对象,强引用,不进行拷贝。
NSMapTable
NSMapTable 为 NSMutableDictionary 的高阶类型。它与 NSPointerArray 类似,可以指定 NSPointerFunctionsOptions,不同的是 NSMapTable 的 key 和 value 都可以指定 options。
传统字典就相当于一个特殊的 NSMapTable把它的 keyOptions 设成这样:
NSPointerFunctionsStrongMemory|NSPointerFunctionsObjectPersonality|NSPointerFunctionsCopyIn
再把它的 valueOptions 设成这样:
NSPointerFunctionsStrongMemory|NSPointerFunctionsObjectPersonality
NSHashTable
NSHashTable 是 NSMutableSet 的高阶类型,与 NSPointerArray、NSMapTable 一样,可以指定 NSPointerFunctionsOptions
NSCache
NSCache是Foundation框架提供的缓存类的实现,使用方式类似于可变字典,由于NSMutableDictionary的存在,很多人在实现缓存时都会使用可变字典,但这样是具有很多局限性的。我们可以从3个方面理清楚它与NSMutableDictionary的区别:
- NSCache集成了多种缓存淘汰策略(虽然官方文档没有明确指出,但从测试结果来看是 LRU 即 Lease Recent Usage),且发生内存警告时会进行清理), 保证了 cache 不会占用过多的内存资源。
- NSCache是线程安全的。可以从不同的线程中对NSCache进行增删改查操作,而不需要自己对cache加锁。
- 与NSMutableDictionary不同, NSCache不会对key进行拷贝。