一、NSDictionary

1.1 使用自定义对象 key

Dictionaries manage pairs of keys and values. A key-value pair within a dictionary is called an entry. Each entry consists of one object that represents the key, and a second object which is that key’s value. Within a dictionary, the keys are unique—that is, no two keys in a single dictionary are equal (as determined by isEqual:). A key can be any object that adopts the NSCopying protocol and implements the hash and isEqual: methods.

字典管理着键值对。键是唯一的,同一个字典里面不会有相同的 key(由 isEqual: 确定),key 可以是遵守 NSCoping 协议并实现 hashisEqual: 方法的任何对象。

- (instancetype)copyWithZone:(NSZone *)zone
{
return self;
}

如果字典很少更改或大量更改,则应使用不可变的字典;否则使用可变字典。

Objects added as values to a dictionary are not copied (unless you pass YES as the argument to initWithDictionary:copyItems:). Rather, a strong reference to the object is added to the dictionary.

作为 value 添加到字典的对象不会被复制(除非调用 initWithDictionary:copyItems: 方法,并且参数传递 YES),而是将对对象的强引用添加到字典中。Copying Collections

You can also add entries from another dictionary using the addEntriesFromDictionary: instance method. If both dictionaries contain the same key, the receiver’s previous value object for that key is released and the new object takes its place.

使用 addEntriesFromDictionary: 从一个已有的字典添加键值对时,相同 key 对应的 value 会被替换。

Keys must conform to the NSCopying protocol. Methods that add entries to dictionaries—whether as part of initialization (for all dictionaries) or during modification (for mutable dictionaries)— don’t add each key object to the dictionary directly. Instead, they copy each key argument and add the copy to the dictionary. After being copied into the dictionary, the dictionary-owned copies of the keys should not be modified.

Keys must implement the hash and isEqual: methods because a dictionary uses a hash table to organize its storage and to quickly access contained objects. In addition, performance in a dictionary is heavily dependent on the hash function used. With a bad hash function, the decrease in performance can be severe. For more information on the hash and isEqual: methods see NSObject.

使用自定义对象 key 时,对象需要遵守 NSCoping 协议,存储数据时,字典会持有 key 的复制,复制到字典中后,不应修改字典拥有的键的副本。

键必须实现 hash 和 isEqual: 方法,因为字典使用哈希表来组织其存储并快速访问所包含的对象。此外,字典的性能在很大程度上取决于所使用的哈希函数。如果哈希函数不正确,性能下降可能会很严重。

注意:不要使用一个很大的对象作为 key,例如 NSImage 对象,这样会导致性能下降。

1.2 NSMapTable

NSMapTable 允许针对特定情况(例如,当您需要高级内存管理选项时或想要保留特定类型的指针时)定制其他的存储选项。如图中的映射表配置为保存对其值对象的弱引用。

还可以指定是否要复制输入到数组中的对象。

The NSMapTable class also defines a number of convenience constructors for creating a map table with strong or weak references to its contents. For example, mapTableWithStrongToWeakObjects creates a map table that holds strong references to its keys and weak references to its values. These convenience constructors should only be used if you are storing objects.

使用 mapTableWithStrongToWeakObjects 可以强引用 key,弱引用 value。

为了能够使用任意的指针,请同时使用 NSPointerFunctionsOpaqueMemoryNSPointerFunctionsOpaquePersonality 值选项对其进行初始化。键和值的 options 不必相同。当使用映射表包含任意指针时,指针类型应该使用 c 语言的 void *。

NSPointerFunctionsOptions keyOptions   = NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality | NSPointerFunctionsCopyIn;
NSPointerFunctionsOptions valueOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality; NSMapTable * mapTable = [NSMapTable mapTableWithKeyOptions:keyOptions valueOptions:valueOptions]; int i = 1;
NSString * key = @"Key";
NSMapInsert(mapTable, key, &i); NSLog(@"Key contains: %i", *(int *) NSMapGet(mapTable, key));

1.3 底层原理

Objective-C 中的字典 NSDictionary 底层其实是一个哈希表。

NSDictionary 使用 hash 表来实现 key 和 value 之间的映射和存储,hash 函数设计的好坏影响着数据的查找访问效率。数据在 hash 表中分布的越均匀,其访问效率越高。而在 Objective-C 中,通常都是利用 NSString 来作为键值,其内部使用的 hash 函数也是通过使用 NSString 对象作为键值来保证数据的各个节点在 hash 表中均匀分布。

字典每个条目存取是通过将字典的键(Key)计算出键的 hash 值,通过查 hash 表获取具体的 value。所以作为 NSDictionary 的键(Key)取值的时候,只要其 key 对象内容地址相同就可以取出相应的值。

二、数组

2.1 NSPointArray

NSPointArray 类似 NSMutableArray,但它可以容纳 nil 值,同 count 值也包含 nil 的数量。它还允许你在定制特定的情况下设置额外的存储选项。

NSPointerArray * arr = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsStrongMemory];
[arr addPointer:nil];
[arr addPointer:@"sss"]; NSLog(@"%lu", arr.count);
NSLog(@"%@", [arr pointerAtIndex:0]);
NSLog(@"%@", [arr pointerAtIndex:1]); arr.count = 1;
NSLog(@"%@", [arr pointerAtIndex:0]);
NSLog(@"%@", [arr pointerAtIndex:1]); // 崩溃。-[NSConcretePointerArray pointerAtIndex:]: attempt to access pointer at index 1 beyond bounds 1'

当您想要使用弱引用的有序集合时,可以使用 NSPointerArray 对象。例如,假设您有一个包含一些对象的全局数组。因为从不收集全局对象,所以除非将其保持为弱状态,否则不能释放其所有内容。配置为弱保存对象的指针数组不拥有其内容。如果在此类指针数组中没有对对象的强引用,则可以释放这些对象。

为了使用任意的指针,可以同时使用 NSPointerFunctionsOpaqueMemoryNSPointerFunctionsOpaquePersonality 选项对其进行初始化。

NSPointerFunctionsOptions options = (NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality);

NSPointerArray * ptrArray = [NSPointerArray pointerArrayWithOptions:options];

int i = 1;
[ptrArray addPointer:&i]; NSLog(@" Index 0 contains: %i", *(int *)[ptrArray pointerAtIndex:0]);

三、数据拷贝

The normal copy is a shallow copy that produces a new collection that shares ownership of the objects with the original. Deep copies create new objects from the originals and add those to the new collection.

通常情况是浅拷贝,它会生成一个新集合,该集合与原始对象共享对象的所有权。深拷贝从原始对象创建新对象,并将其添加到新集合中。

When you create a shallow copy, the objects in the original collection are sent a retain message and the pointers are copied to the new collection.

浅拷贝时,原始数据集合中的对象会发送 retain 消息,并将指针拷贝到新数据集合中。

You can use the collection’s equivalent of initWithArray:copyItems: with YES as the second parameter. If you create a deep copy of a collection in this way, each object in the collection is sent a copyWithZone: message. If the objects in the collection have adopted the NSCopying protocol, the objects are deeply copied to the new collection, which is then the sole owner of the copied objects. If the objects do not adopt the NSCopying protocol, attempting to copy them in such a way results in a runtime error. However, copyWithZone: produces a shallow copy. This kind of copy is only capable of producing a one-level-deep copy.

使用 copyItem:YES 方法时,会给集合中的每个对象发送 copyWithZone: 消息。如果对象实现了 NSCopying 协议,那么这些对象会被深拷贝到新的数据集合;如果没有实现协议,则会导致运行时错误。

然而 copyWithZone: 生成的是浅层的“深拷贝”,只是做了一层的深拷贝,如果数据是多层数组嵌套的话,则第二层、第三层...的数据没有进行深拷贝。

If you need a true deep copy, such as when you have an array of arrays, you can archive and then unarchive the collection, provided the contents all conform to the NSCoding protocol.

如果想真正的深拷贝,只要内容全部符合 NSCoding 协议,则可以存档然后取消存档该集合。

NSArray * trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObjectoldArray]];

复制集合时,该集合或其包含的对象的可变性可能会受到影响。

  • copyWithZone: makes the surface level immutable. All deeper levels have the mutability they previously had. 第一层是可变的,其余深层还是以前的可变性。

  • initWithArray:copyItems: with NO as the second parameter gives the surface level the mutability of the class it is allocated as. All deeper levels have the mutability they previously had. 第一层保持分配时的可变性,其余深层还是以前的可变性

  • initWithArray:copyItems: with YES as the second parameter gives the surface level the mutability of the class it is allocated as. The next level is immutable, and all deeper levels have the mutability they previously had.
    Archiving and unarchiving the collection leaves the mutability of all levels as it was before. 第一层保持分配时的可变性,第二层是可变的,其余深层还是以前的可变性

四、文章

Dictionaries: Collections of Keys and Values

NSArray、NSDictionary的更多相关文章

  1. Foundation框架之NSArray、NSDictionary、NSSet及其Mutable类型

    Foundation框架之NSArray.NSDictionary.NSSet及其Mutable类型 目录 概述——对Foundation框架集合类的理解 NSArray NSDictionary N ...

  2. iOS 将NSArray、NSDictionary转换为JSON格式进行网络传输

    http://blog.csdn.net/worldzhy/article/details/49982491 将NSArray.NSDictionary转换为JSON格式进行网络传输,是经常用到的,但 ...

  3. 在Objective-C 中使用字符生成NSArray、NSDictionary、NSNumber

    @符号不仅可以生成字符串,还可以生成其他数据类型如NSArray.NSDictionary和NSNumber,是一种简洁快速的用法. // NSArray array = [NSArray array ...

  4. OC 解决NSArray、NSDictionary直接打印中文出现乱码的问题

    在iOS开发中,经常需要查看数组中得元素是否是自己想要的,但是苹果并没有对直接打印数组中得中文作处理,直接打印就会出现一堆很讨厌的东西,解决其实很简单,就是需要通过为NSArray添加分类,重写 - ...

  5. NSString、NSArray、NSDictionary和NSData的数据存储

    #import "ViewController.h" @interface ViewController () @end @implementation ViewControlle ...

  6. 放在NSArray、NSDictionary等容器内的对象Item,Item中的property在程序运行过程中被无故释放

    可能是被释放的property本身是OC对象而它的属性被误写成assign,例如: @interface MyItem : Object @property (nonatomic, assign) N ...

  7. 用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?

    因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本. 如果我们使用是 str ...

  8. 04-Foundation-NSSet、NSDictionary、block

    目录: 一.NSSet集合 二.NSDictionary字典 三.block代码块 回到顶部 一.NSSet集合 1 NSSet是一个无序的,管理对个对象的集合类,最大特点是集合中不允许出现重复对象, ...

  9. iOS-NSBundle、NSArray、NSDictionay

    NSBundle.NSArray.NSDictionay 读取plist文件 NSDictionary  *dict= [NSDictionary dictionaryWithContentsOfFi ...

随机推荐

  1. iMX287A多种方法实现流水灯效果

    目录 1.流水灯在电子电路中的地位 2.硬件电路分析 3.先点个灯吧 4.shell脚本实现流水灯 5.ANSI C文件操作实现流水灯 6.Linux 系统调用实现流水灯 @ 1.流水灯在电子电路中的 ...

  2. Day 3 DP

    1. P1015 精卫填海 01背包 + 判断 #include <iostream> using namespace std; , MAXV = ; int v, n, m, f[MAX ...

  3. pip install mysqlclient报错(OSError: mysql_config not found)

    报错截图 一般情况是系统没有安装libmysqld-dev 执行 sudo apt install libmysqld-dev完成安装后再 pip install mysqlclient就可以了(系统 ...

  4. CSS中"position:relative"属性与文档流的关系

    前言 近期遇到一个问题--"position:relative"到底会不会导致元素脱离文档流?主流观点是不会,但都给不出一个有说服力的论据.最后我自己佐证了一番,总算有了个结果:& ...

  5. 【Amaple教程】6. 路由配置

    在 第1节<启动路由> 章节中为了能让单页应用顺利跑起来,我们提前介绍了简单的路由配置方法.我们已了解路由配置的目的是指定不同的url下对应的 模块节点(也叫做模块容器)内应该显示哪个模块 ...

  6. 前端每日实战:4# 视频演示如何用纯 CSS 创作一个金属光泽 3D 按钮特效

    效果预览 按下右侧的"点击预览"按钮在当前页面预览,点击链接全屏预览. https://codepen.io/zhang-ou/full/MGeRRO 可交互视频教程 此视频是可以 ...

  7. Python - 超好用的第三方库pathlib,快速获取项目中各种路径

    前言 之前曾介绍过Python的os库详细使用方式,具体可看看这篇博文:https://www.cnblogs.com/poloyy/p/12341231.html 博主在学完os库之后,就开始投入使 ...

  8. JS模块规范:AMD,CMD,CommonJS

    浅析JS模块规范 随着JS模块化编程的发展,处理模块之间的依赖关系成为了维护的关键. AMD,CMD,CommonJS是目前最常用的三种模块化书写规范. CommonJS CommonJS规范是诞生比 ...

  9. VS2017配置opencv-4.2.0详细步骤

    VS2017配置opencv-4.2.0详细步骤   1.下载opencv的安装包并解压.下载网址https://sourceforge.net/projects/opencvlibrary/ 图1 ...

  10. [日志分析]Graylog2采集mysql慢日志

    之前聊了一下graylog如何采集nginx日志,为此我介绍了两种采集方法(主动和被动),让大家对graylog日志采集有了一个大致的了解. 从日志收集这个角度,graylog提供了多样性和灵活性,大 ...