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都进行了深拷贝,没有违背我们的意愿


猜你喜欢

转载自blog.csdn.net/qq_39551390/article/details/81133087
今日推荐