欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

strong、copy,深拷贝、浅拷贝

程序员文章站 2024-01-15 08:53:52
...

文中所引用的对象如下解释,顾名思义,简单易懂

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