美文网首页
iOS 容器(NSArray,NSDictionary,NSSe

iOS 容器(NSArray,NSDictionary,NSSe

作者: qui丶MyLove | 来源:发表于2021-07-17 19:49 被阅读0次

    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
    原贴

    相关文章

      网友评论

          本文标题:iOS 容器(NSArray,NSDictionary,NSSe

          本文链接:https://www.haomeiwen.com/subject/jbqbpltx.html