strong、copy,深拷贝、浅拷贝
文中所引用的对象如下解释,顾名思义,简单易懂
master.muStrStrong 指的用strong修饰的可变字符串
master.muStrCopy 指的用copy修饰的可变字符串
master.strStrong 指的是用strong修饰的不可变字符串
master.strCopy 指的是用copy修饰的不可变字符串
1.可变用strong的原因
NSMutableString应该使用strong类型,NSString使用copy类型,copy生成的是不可变对象,即用copy类型会强制将NSMutableString转换为NSString类型,所以无法使用NSMutableString的appendString等等方法,导致crash。
master.muStrCopy = [NSMutableString stringWithString:@"123"];
[master.muStrCopy appendString:@"33"];//执行到这句时 crash!!!!!!
2.不可变用copy的原因
假如有一个NSMutableString,现在用他给一个strong修饰 NSString赋值,那么只是将NSString指向了NSMutableString所指向的位置,并对NSMUtbaleString计数器加一,此时,如果对NSMutableString进行修改,也会导致NSString的值修改,原则上这是不允许的.
例如
master.muStrStrong = [NSMutableString stringWithString:@"123"];
master.strStrong = master.muStr;
[master.muStrStrong appendString:@"33"];
NSLog(@"------%@,,,,%@",master.muStrStrong,master.strStrong);
打印结果:
——12333,,,,12333
改变了可变字符串的值后,不可变字符串也跟着改变,让我们来看看它们的地址
打印地址后发现,他们指向了同一块地址
—–0x10066c830,,,,0x10066c830
此时,不可变字符串在某种程度真的变成了可变字符串,所以这样的结果是很荒谬的。
如果是copy修饰的NSString对象,在用NSMutableString给他赋值时,会进行深拷贝,及把内容也给拷贝了一份,两者指向不同的位置,即使改变了NSMutableString的值,NSString的值也不会改变.
所以用copy是为了安全,防止NSMutableString赋值给NSString时,前者修改引起后者值变化而用的.
3.深、浅拷贝
当使用NSString(A)给NSString(B)赋值,当B为copy的时候也不会生成2个内存空间,而是指向同一个指针,即为浅拷贝,当NSMutablestring(A)给NSString(B)赋值,当B为copy的时候会生成2个内存空间,即为深拷贝。
非集合类对象的copy与mutableCopy
系统非集合类对象指的是 NSString, NSNumber … 之类的对象。
下面先看个非集合类unmutable对象拷贝的例子
NSString *string =
@"origin";
NSString *stringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];
打印内存地址
string = 0x1000eda78
stringCopy = 0x1000eda78
stringMCopy = 0x17407e8c0
可以看到stringCopy和string的地址是一样,说明进行了指针拷贝;而stringMCopy的地址和string不一样,说明进行了内容拷贝;
再看mutable对象拷贝例子
NSMutableString *mString = [NSMutableString stringWithString:@"origin"];
NSString *stringCopy = [mString copy];
NSMutableString *mStringCopy = [mString copy];
NSMutableString *mStringMCopy = [mString mutableCopy];
[mStringCopy appendString:@"ww"];
运行上述代码会在最后一行[mStringCopy appendString:@”mm”];处crash,原因是copy返回的对象是unmutable对象,删掉该行,再次运行,打印内存地址
mString = 0x174266940
stringCopy = 0x1742294a0
mStringCopy = 0x1742294c0
mStringMCopy = 0x174266980
会发现四个对象的内存地址都不一样,说明此时都是做内容拷贝。
综上两个例子,我们可以得出结论:
在非集合类对象中:
对unmutable对象进行copy操作是指针复制,mutableCopy操作是内容复制;
对mutable对象进行copy和mutableCopy都是内容复制。
用代码简单表示如下:
[unmutableObject copy] // 浅复制
[unmutableObject mutableCopy] //深复制
[mutableObject copy] //深复制
[mutableObject mutableCopy] //深复制
附:集合类对象的copy与mutableCopy的理论与其相同,不过此处的内容拷贝,仅仅是拷贝array这个对象,array集合内部的元素仍然是指针拷贝。
我们来看看一个例子
NSString *str0 = @"1";
NSString *str1 = @"2";
NSString *str2 = @"3";
NSMutableArray *muArraySource = [[NSMutableArray alloc]initWithObjects:str0,str1,str2,nil];
NSMutableArray *muArray = [[NSMutableArray alloc]init];
muArray = [muArraySource copy];
NSLog(@"%p,,,%p,,,%p",str0,str1,str2);
NSLog(@"%p,,,%p",muArray,muArraySource);
NSLog(@"%p,,,%p,,,%p",[muArraySource objectAtIndex:0],[muArraySource objectAtIndex:1],[muArraySource objectAtIndex:2]);
muArray = 0x100778c10
master.muArrayStrong = 0x1007787e0
正如我们所了解的,不可变集合执行copy进行了深拷贝
我们再来看看元素地址的变化
str0 = 0x100002068
[muArraySource objectAtIndex:0] = 0x100002068
str1 = 0x100002088
[muArraySource objectAtIndex:1] = 0x100002068
str2 = 0x1000020a8
引用块内容
[muArraySource objectAtIndex:2] = 0x1000020a8
结果已经很明确了,可变数组进行了深拷贝,而其里面的元素只进行了指针拷贝,即浅拷贝。
4.进一步的探索
1). 对于不可变对象的copy,属于浅拷贝,无论被赋值对象是copy还是strong,都指向了这块地址。
Master *master = [[Master alloc]init];
NSString *temp = [[NSString alloc]init];
temp = @"123";
master.strCopy = [temp copy];
master.strStrong = [temp copy];
NSLog(@"%p,,,,%p,,,,%p",temp,master.strCopy,master.strStrong);
temp = @"222";
NSLog(@"%p,,,,%p,,,,%p",temp,master.strCopy,master.strStrong);
NSLog(@"%@,,,,%@,,,,%@",temp,master.strCopy,master.strStrong);
0x100002068,,,,0x100002068,,,,0x100002068
当不可变字符串改变后,其内存会发生变化,可它们原来的指针仍指向这块内存
0x100002088,,,,0x100002068,,,,0x100002068
222,,,,123,,,,123
2). [master.muStrStrong copy]; 不等于 master.muStrStrong
先看 [master.muStrStrong copy]; 的实例
Master *master = [[Master alloc]init];
master.muStrStrong = [NSMutableString stringWithString:@“123”];
master.strCopy = [master.muStr copy];
master.strStrong = [master.muStr copy];
NSLog(@"%p,,,,%p,,,,%p",master.muStrStrong,master.strCopy,master.strStrong);
[master.muStrStrong appendString:@"33"];
NSLog(@"------%p,,,,%p,,,,%p",master.muStrStrong,master.strCopy,master.strStrong);
master.muStrStrong = 0x10063c800
master.strCopy = 0x33323135
master.strStrong = 0x33323135
可变字符串改变后
master.muStrStrong = 0x10063c800
master.strCopy = 0x33323135
master.strStrong = 0x33323135
于是,muStrStrong执行copy进行了深拷贝,生成了新的对象,无论是copy还是strong修饰的字符串都指向了新生成对象的内存。我们也知道了,可变字符发生改变时所在地址不会发生变化。
再看 master.muStrStrong 的实例
master.muStrStrong = [NSMutableString stringWithString:@"123"];
master.strCopy = master.muStrStrong;
master.strStrong = master.muStrStrong;
[master.muStrStrong appendString:@"33"];
NSLog(@"%p,,,,%p,,,,%p",master.muStrStrong,master.strCopy,master.strStrong);
master.muStrStrong = 0x10050a800
master.strCopy = 0x3332313
master.strStrong = 0x10050a800
此时strCopy进行了深拷贝,就如同赋值的muStrStrong执行copy一样。
但是这两种情况无论如何用copy修饰的NSString都进行了深拷贝,没有违背我们的意愿
上一篇: cocoa编码指南(翻译)