iOS 容器(NSArray,NSDictionary,NSSet等)

ios中常见容器

  • array:存储一组有序的值
  • set:存储一组无序的值
  • dictionary:存储一组无序的key-value映射
其他高阶
  • NSCountedSet
  • NSIndexSet && NSMutableIndexSet
  • NSOrderedSet && NSMutableOrderedSet
  • NSPointerArray
  • NSMapTable
  • NSHashTable
  • NSCache
  1. NSArray
    数组在内存上是连续存储空间,可以通过index下标获取数组元素。
  2. NSSet
    集合在内存上是不连续的,相同元素只能存在一个,一种哈希表,运用散列算法,查找集合中的元素比数组速度更快,但是它没有顺序。
  3. NSDictionary
    字典在内存上是不连续的,通过key-value映射。一种哈希表,通过哈希算法得到key的哈希值去表中查对应的value,它没有顺序。
图示1
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的性能上比较

图示2

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进行拷贝。

demo-git
原贴

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容