iOS中深复制和浅复制问题

时间:2022-01-29 03:44:42

NSDictionary对象,添加内容,然后通过代码产生可变和不可变副本,这些复制是深复制还是浅复制?那么对于可变对象呢?为什么NSString定义属性时需要用copy呢?copy属性和copy对象有什么不同?

首先先说一下copyretain的区别:

  copy是创建一个新对象,是内容拷贝。retain是创建一个指针,引用对象计数加1retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain+1。

对于深复制和浅复制我们来看下面的代码:

NSDictionary *dict = [NSDictionarydictionaryWithObjectsAndKeys:@"1",@"1",@"2",@"2",nil];

    NSLog(@"原字典:%p",dict);

    

    NSDictionary *dictRetain = dict.retain;

    NSLog(@"计数器:%p",dictRetain);

    

    NSDictionary *dictCopy = dict.copy;

    NSLog(@"浅复制:%p",dictCopy);

    

    NSMutableDictionary *dictMutableCopy = dict.mutableCopy;

    NSLog(@"深复制:%p",dictMutableCopy);

打印结果:


原字典:0x7f7f89d21ec0

计数器:0x7f7f89d21ec0

浅复制:0x7f7f89d21ec0

深复制:0x7f7f89c09680


 也就是说,对于retaincopy产生的字典内存与原地址内存相同,也就是说copy产生的不可变版本是浅复制和retain一样拷贝的是指针。而mutableCopy深复制是拷贝的对象内容。


下面我们看一个可变对象的拷贝过程:

NSMutableString *string = [NSMutableStringstringWithString:@"name"];

    NSLog(@"strP:%p",string);

    

    NSString *stringCopy = [stringcopy];

    NSLog(@"copy:%p",stringCopy);

    

    NSMutableString *mStringCopy = [stringcopy];

    NSLog(@"copy:%p",mStringCopy);

    

    NSMutableString *stringMCopy = [stringmutableCopy];

    NSLog(@"mCopy:%p",stringMCopy);


打印结果:

    strP:0x7faea1f124d0

    copy:0xa000000656d616e4

    copy:0xa000000656d616e4

    mCopy:0x7faea1e0df20

对于可变对象进行复制,结果和上面不一样了。

我们可以这样理解:如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。


还有一个问题就是:我们知道,在@property属性里copy说的是复制了一个新的对象,引用计数不加1.那么这里属性copy则是使用了深复制。而调用copy方法则是做了一个浅复制。

这也就是为什么NSString属性变量要用copy关键字。如果把一个NSString赋值给NSMutableString属性时,如果使用了strong,则相当于浅复制。两个指针指向同一块内存,当NSMutableString改变后,NSString也就改变了。如果使用了copy,则是深复制。两个对象存在于不同的内存中,当NSMutableString改变时,不影响NSString.


另外,对于字符串来说,我们在使用的时候还要注意:

 initWithFormat会创建新空间,initWithString不一定创建新空间,取决于参数。如果后面是常量字符串则不会创建新空间,如果是定义新字符串,则会创建新空间。下面是测试代码:


NSString *name = [[NSString alloc]initWithFormat:@"张三"];

    NSString *name = [[NSStringalloc]initWithString:@"张三"];

    

    NSLog(@"%ld",[nameretainCount]);

    [name retain];

    NSLog(@"%ld",[nameretainCount]);

    [name copy];

    NSLog(@"%ld",[nameretainCount]);

    [name mutableCopy];

    NSLog(@"%ld",[nameretainCount])

结果:如果是initWithString,则输入结果全为-1,如果是initWithFormat,结果分别是:1,2,3,4