你不得不知道的iOS 中的 Copying

Copying 在 iOS 中有很多概念,例如浅拷贝与深拷贝、copy 与 mutableCopy、NSCopying 协议,一直想彻底搞明白这些概念,刨根问底不搞懂不罢休嘛。于是搜 Google 看了一些博客,又去翻了 Apple 相关的文档,发现网上许多博客都理解错了,下面说说自己的理解。

浅拷贝与深拷贝

对于浅拷贝(Swallow Copy)与深拷贝(Deep Copy),经常看到这样的说法:浅复制是指针拷贝,仅仅拷贝指向对象的指针;深复制是内容拷贝,会拷贝对象本身。 这句话并没有说错,但需要注意的是指针/内容拷贝针对的是谁,无论浅拷贝还是深拷贝,被拷贝的对象都会被复制一份,有新的对象产生,而在复制对象的内容时,对于被拷贝对象中的指针类型的成员变量,浅拷贝只是复制指针,而深拷贝除了复制指针外,会复制指针指向的内容。下面我们以 Apple 官方文档中的图片进行说明:

ios-object-copy.png

对普通对象 ObjectA 进行 copy,无论浅拷贝还是深拷贝,都会复制出一个新的对象 ObjectB,只是浅拷贝时 ObjectA 与 ObjectB 中的 textColor 指针还指向同一个 NSColor 对象,而深拷贝时 ObjectA 和 ObjectB 中的 textColor 指针分别指向各自的 NSColor 对象(NSColor 对象被复制了一份)。

CopyingCollections_2x.png

对集合对象 Array1 进行 copy,无论浅拷贝还是深拷贝,都会复制出一个新的对象 Array2,只是浅拷贝时 Array1 与 Array2 中各个元素的指针还指向同一个对象,而深拷贝时 Array1 和 Array2 中各个元素的指针分别指向各自的对象(对象被复制了一份)。

Copy 与 MutableCopy

在说明 copy 与 mutableCopy 之前,我们思考一下:拷贝的目的是什么?在动态库加载时,只读的 TEXT 段是被所有使用动态库的程序共享的, 而可写的 DATA 段会使用 COW(Copy On Write)技术,当某个程序需要修改 DATA 段时会拷贝一份,供此程序专用。因此,拷贝的目的主要用于拷贝一份新的数据进行修改,而不会影响到原有的数据。如果不修改,拷贝就没有必要。

在 iOS 中,有一些系统类根据是否可变进行了区分,例如 NSString 与 NSMutableString,NSArray 与 NSMutableArray 等。为了在两者之间进行转换(我理解这是主要目的),NSObject 提供了 copy 与mutableCopy 方法, copy 复制后对象是不可变对象,mutableCopy 复制后对象是可变对象。对象有不可变对象和可变对象,复制方法有 copy 和 mutableCopy,因此存在四种情况:

  • 不可变对象 copy:对象是不可变的,再复制出一份不可变对象没有意义,因此根本没有发生任何拷贝,对象只有一份。

  • 不可变对象 mutableCopy:可变对象的能够修改,原来的不可变对象不支持,因此需要复制出一个新对象,是浅拷贝。

  • 可变对象 copy:不可变对象不能修改,原来的可变对象不支持,因此需要复制出新对象,是浅拷贝。

  • 可变对象 mutableCopy:可变对象的修改不应该影响到原来的可变对象,因此需要复制出新对象,是浅拷贝。

如何进行深拷贝呢?

对于集合类型的对象,将 initWithArray:copyItems: 第二个参数设置成 YES 时,会对集合内每一个元素发送 copyWithZone: 消息,元素进行复制,但是对于元素中指针类型的成员变量,依然是浅拷贝,因此这种拷贝被称为单层深拷贝(one-level-deep copy)。

如果想进行完全的深拷贝,可以先通过 NSKeyedArchiver 将对象归档,再通过 NSKeyedUnarchiver 将对象解归档。由于在归档时,对象中每个成员变量都会收到 encodeWithCoder: 消息,相当于将对象所有的数据均序列化保存到磁盘上(可以看成换了种数据格式的拷贝),再通过 initWithCoder: 解归档时,就将拷贝过的数据经过转换后读取出来,深拷贝。

NSCopying

如果自定义的类也想要支持 copy 和 mutableCopy 方法,就需要实现 NSCopying 和NSMutableCopying 协议。在实现 copyWithZone: 方法时需要注意:

  • copyWithZone: 相当于新创建一个对象,并将当前对象的值复制到新创建的对象中。设置时应直接访问成员变量而不是通过属性访问。

  • 直接从 NSObject 继承的类,应使用 [[[self class] allocWithZone:zone] init],使得在创建新对象时能够使用正确的类。

  • 父类中已经实现了 copyWithZone: 时,应先调用父类的方法,让父类创建对应的对象(self class 能保证创建对象是正确的),并拷贝父类中定义的成员变量。

1
2
3
4
5
- (id)copyWithZone:(NSZone *)zone {
     YourClass *object = [ super  copyWithZone:zone];
     _property = xxx;
     return  object;
}
优秀的个人博客,低调大师

微信关注我们

原文链接:https://yq.aliyun.com/articles/590235

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
优质分享Android(本站安卓app)

优质分享Android(本站安卓app)

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Eclipse(集成开发环境)

Eclipse(集成开发环境)

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。

Sublime Text 一个代码编辑器

Sublime Text 一个代码编辑器

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。