概念数组
对象拷贝有两种方式:浅复制和深复制。顾名思义,浅复制,并不拷贝对象自己,仅仅是拷贝指向对象的指针;深复制是直接拷贝整个对象内存到另外一块内存中。app
一图以蔽之spa
再简单些说:浅复制就是指针拷贝;深复制就是内容拷贝。.net
________________________________________指针
集合的浅复制(shallow copy)code
集合的浅复制有很是多种方法。当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合。对象
如今让咱们看一些浅复制的例子:blog
1接口 2内存 3 4 5 6 |
|
集合的深复制(deep copy)
集合的深复制有两种方法。能够用initWithArray:copyItems:将第二个参数设置为YES便可深复制,如
1 |
|
若是你用这种方法深复制,集合里的每一个对象都会收到copyWithZone:消息。若是集合里的对象遵循NSCopying协议,那么对象就会被深复制到新的集合。若是对象没有遵循NSCopying协议,而尝试用这种方法进行深复制,会在运行时出错。copyWithZone:这种拷贝方式只可以提供一层内存拷贝(one-level-deepcopy),而非真正的深复制。
第二个方法是将集合进行归档(archive),而后解档(unarchive),如:
1 |
|
________________________________________
集合的单层深复制(one-level-deep copy)
看到这里,有同窗会问:若是在多层数组中,对第一层进行内容拷贝,其它层进行指针拷贝,这种状况是属于深复制,仍是浅复制?对此,苹果官网文档有这样一句话描述
This kind of copy is only capable of producing a one-level-deep copy. If you only need a one-level-deep copy...
If you need a true deep copy, such as when you have an array of arrays...
从文中能够看出,苹果认为这种复制不是真正的深复制,而是将其称为单层深复制(one-level-deepcopy)。所以,网上有人对浅复制、深复制、单层深复制作了概念区分。
浅复制(shallowcopy):在浅复制操做时,对于被复制对象的每一层都是指针复制。
深复制(one-level-deepcopy):在深复制操做时,对于被复制对象,至少有一层是深复制。
彻底复制(real-deepcopy):在彻底复制操做时,对于被复制对象的每一层都是对象复制。
固然,这些都是概念性的东西,没有必要纠结于此。只要知道进行拷贝操做时,被拷贝的是指针仍是内容便可。
________________________________________
系统对象的copy与mutableCopy方法
不论是集合类对象,仍是非集合类对象,接收到copy和mutableCopy消息时,都遵循如下准则:
copy返回imutable对象;因此,若是对copy返回值使用mutable对象接口就会crash;
mutableCopy返回mutable对象;
下面将针对非集合类对象和集合类对象的copy和mutableCopy方法进行具体的阐述
一、非集合类对象的copy与mutableCopy
系统非集合类对象指的是NSString,NSNumber...之类的对象。下面先看个非集合类immutable对象拷贝的例子
1 2 3 |
|
经过查看内存,能够看到stringCopy和string的地址是同样,进行了指针拷贝;而stringMCopy的地址和string不同,进行了内容拷贝;
再看mutable对象拷贝例子
1 2 3 4 5 6 7 8 9 |
|
运行以上代码,会在第7行crash,缘由就是copy返回的对象是immutable对象。注释第7行后再运行,查看内存,发现string、stringCopy、mStringCopy、stringMCopy四个对象的内存地址都不同,说明此时都是作内容拷贝。
综上两个例子,咱们能够得出结论:
在非集合类对象中:对immutable对象进行copy操做,是指针复制,mutableCopy操做时内容复制;对mutable对象进行copy和mutableCopy都是内容复制。用代码简单表示以下:
[immutableObjectcopy]//浅复制
[immutableObjectmutableCopy]//深复制
[mutableObjectcopy]//深复制
[mutableObjectmutableCopy]//深复制
二、集合类对象的copy与mutableCopy
集合类对象是指NSArray、NSDictionary、NSSet...之类的对象。下面先看集合类immutable对象使用copy和mutableCopy的一个例子:
1 2 3 |
|
查看内容,能够看到copyArray和array的地址是同样的,而mCopyArray和array的地址是不一样的。说明copy操做进行了指针拷贝,mutableCopy进行了内容拷贝。但须要强调的是:此处的内容拷贝,仅仅是拷贝array这个对象,array集合内部的元素仍然是指针拷贝。这和上面的非集合immutable对象的拷贝仍是挺类似的,那么mutable对象的拷贝会不会相似呢?咱们继续往下,看mutable对象拷贝的例子:
1 2 3 |
|
查看内存,如咱们所料,copyArray、mCopyArray和array的内存地址都不同,说明copyArray、mCopyArray都对array进行了内容拷贝。一样,咱们能够得出结论:
在集合类对象中,对immutable对象进行copy,是指针复制,mutableCopy是内容复制;对mutable对象进行copy和mutableCopy都是内容复制。可是:集合对象的内容复制仅限于对象自己,对象元素仍然是指针复制。用代码简单表示以下:
[immutableObjectcopy]//浅复制
[immutableObjectmutableCopy]//单层深复制
[mutableObjectcopy]//单层深复制
[mutableObjectmutableCopy]//单层深复制
这个代码结论和非集合类的很是类似。
这时候,是否是有人要问了,若是要对集合对象复制元素怎么办?有这疑问的同窗不妨回头看看集合的深复制。
好了,深复制与浅复制就讲到这里。
________________________________________
最后说个题外的东西,在搜集资料的过程当中,发现一个有可能犯错的点
1 2 |
|
上面这段代码,在执行第二行代码后,内存地址发生了变化。乍一看,有点意外。按照C语言的经验,初始化一个字符串以后,字符串的首地址就被肯定下来,无论以后如何修改字符串内容,这个地址都不会改变。但此处第二行并非对str指向的内存地址从新赋值,由于赋值操做符左边的str是一个指针,也就是说此处修改的是内存地址。
因此第二行应该这样理解:将@"newStirng"当作一个新的对象,将这段对象的内存地址赋值给str。
我有以下的两个方法查看内存地址
pstr会打印对象自己的内存地址和对象内容
1 2 |
|
po&str则打印的是引用对象的指针所在的地址
1 2 |
|