美文网首页
深拷贝浅拷贝

深拷贝浅拷贝

作者: C_HPY | 来源:发表于2016-06-30 10:10 被阅读172次

    参考链接:

    ios深拷贝,浅拷贝,拷贝自定义对象的简单介绍 - daiyelang的专栏 - 博客频道 - CSDN.NET 

    IOS ----- 对象复制_Ives_新浪博客 

    copy分为深拷贝、浅拷贝。copy的目的是改变副本的时候不影响原对象。

    copy的方法有:

    - (id)copy;

    - (id)mutableCopy;

    深拷贝:内容拷贝(对象中的每一个变量都进行了拷贝),创建了新的对象,新对象引用计数为1,原对象引用计数不变。

    浅拷贝:指针拷贝,没有创建新对象,原对象引用计数增加1。

    一个对象想要支持copy就必须遵从 NSCopying 或者 NSMutableCopying
    协议,Foundation框架下默认支持copy的对象类型有:NString、NSArray、NSNumber、NSDictionar、NSMutableString、NSMutablerArray、NSMutableDictionary等,我们也可以让自定义对象支持复制,前提就是必须遵循NSCopying或者NSMutableCopying协议。

    以下以字符串为例:

    1.不可变字符串调用copy实现拷贝。(浅拷贝)

    NSString *originalStr = [[NSString alloc] initWithString:@"abcde"];

    NSLog(@"originalStr.retainCount  %p",originalStr);

    NSString *newStr = [originalStr copy];

    NSLog(@"originalStr.retainCount  %p",originalStr);

    NSLog(@"newStr.retainCount  %p",newStr);

    打印结果如下:

    originalStr.memoryAddress  0x100004230

    originalStr.memoryAddress  0x100004230

    newStr.memoryAddress  0x100004230

    newStr的地址和originalStr的地址相同,可知不可变字符串调用copy为浅拷贝(指针拷贝),联想本篇开头说的:copy的目的是改变副本的时候不影响源对象,因为源对象本身就是不可变的,所以这里使用简单的浅拷贝(指针拷贝)即可实现不影响源对象的需求(也是为了性能着想),所有此处copy直接就返回了源对象。

    2. 不可变字符串调用mutableCopy实现拷贝 (深拷贝)

    NSString *originalStr = [[NSString alloc] initWithString:@"abcde"];

    NSLog(@"originalStr.memoryAddress  %p",originalStr);

    NSMutableString *newStr = [originalStr mutableCopy];  //返回对象是可变的。

    NSLog(@"originalStr.memoryAddress  %p",originalStr);

    NSLog(@"newStr.memoryAddress  %p",newStr);

    打印地址如下:

    originalStr.memoryAddress  0x100004230

    originalStr.memoryAddress  0x100004230

    newStr.memoryAddress  0x100400000

    newStr的地址与originalStr的地址不同,可知是创建了新的对象。是深拷贝

    3.可变字符串调用copy(深拷贝)

    NSMutableString *originalStr = [NSMutableString stringWithFormat:@"%@",@"abcde"];

    NSLog(@"originalStr.memoryAddress  %p",originalStr);

    NSString *newStr = [originalStr copy];

    NSLog(@"originalStr.memoryAddress  %p",originalStr);

    NSLog(@"newStr.memoryAddress  %p",newStr);

    打印地址如下:

    originalStr.memoryAddress  0x100206d70

    originalStr.memoryAddress  0x100206d70

    newStr.memoryAddress  0x656463626155

    newStr的地址与originalStr的地址不同,可知也进行了深拷贝。

    4.可变字符串调用mutableCopy(深拷贝)

    NSMutableString *originalStr = [NSMutableString stringWithFormat:@"%@",@"abcde"];

    NSLog(@"originalStr.memoryAddress  %p",originalStr);

    NSMutableString *newStr = [originalStr mutableCopy]; //返回字符串为可变的

    NSLog(@"originalStr.memoryAddress  %p",originalStr);

    NSLog(@"newStr.memoryAddress  %p",newStr);

    //newStr拼接字符串,查看是否会影响originalStr

    [newStr appendFormat:@"just a test!"];

    NSLog(@"originalStr=======%@",originalStr);

    NSLog(@"newStr============%@",newStr);

    打印结果如下:

    originalStr.memoryAddress  0x100206d70

    originalStr.memoryAddress  0x100206d70  //原可变字符串地址

    newStr.memoryAddress  0x100300600   //newStr字符串地址

    originalStr=======abcde     //newStr拼接后原字符串内容

    newStr============abcdejust a test!  //newStr拼接后newStr字符串内容

    originalStr和newStr的地址不同,说明创建了新的对象。newStr可进行拼接,说明返回的是可变字符串。

    结论:只有不可变对象使用copy的时候才是浅拷贝(指针拷贝),其它三种情况均是深拷贝(内容拷贝)。

    实现自定义对象的copy:

    1 创建model类 House

    @property (nonatomic, copy) NSString *houseId

    @property (nonatomic, copy) NSString *houseAddress;

    @property (nonatomic, copy) NSString *housePics;

    2 遵循协议<NSCopying>

    3 实现- (id)copyWithZone:(NSZone*)zone方法

    - (id)copyWithZone:(NSZone *)zone

    {

    House *house = [[[self class] allocWithZone:zone] init];

    house.houseId = [_houseId copy];

    house.houseAddress = [_houseAddress copy];

    house.housePics = [_housePics copy];

    return house;

    }

    在使用该类对象的地方即可使用copy复制该对象。

    问题思考:在属性中修饰NSString,NSArray等不可变类型的属性为什么用copy比较合适,用strong进行修饰会出现什么问题?

    直接上代码。。。

    假设House中的houseId使用strong进行修饰:

    @property (nonatomic, strong) NSString *houseId;

    在main.m文件中实现如下代码:

    NSMutableString *muStr = [NSMutableString stringWithFormat:@"%@",@"15000"];  //可变字符串

    House *house = [[House alloc] init];

    house.houseId = muStr;  //为houseId赋值

    NSLog(@"house.houseId  %@",house.houseId);  //第一次houseId的结果

    [muStr appendFormat:@"----------16000"];  //修改muStr的内容

    NSLog(@"house.houseId  %@",house.houseId);

    打印结果如下:

    house.houseId  15000

    house.houseId  15000----------16000

    此时的打印结果显示,house.houseId发生了改变,而事实上houseId是NSString类型的数据,程序就会发生隐形bug。至于问题出现的原因在house.m中,代码如下

    此时在House.m文件中,setterHouseId事实上是这样的

    - (void)setHouseId:(NSString *)houseId

    {

    if (![_houseId isEqualToString:houseId]) {  

    [_houseId release];  

    _houseId = [houseId retain];   //houseId是可变的字符串,strong进行修饰的情况下这里只是进行了额retain操作。只是简单的浅拷贝,所有会出现问题。

    }

    }

    把NSString类型的houseId使用copy进行修饰,打印结果如下:

    house.houseId  15000

    house.houseId  15000

    此时houseId不会发生异常,原因如下:

    - (void)setHouseId:(NSString *)houseId

    {

    if (![_houseId isEqualToString:houseId]) {

    [_houseId release];

    _houseId = [houseId copy];//在使用copy修饰的情况下,houseId是一个可变的字符串,进行了copy操作,进行了额深拷贝,创建了一个新的不可变字符串赋值给了_houseId,所以每次进行setter操作都创建了一个新的不可变字符串,不会发生问题。

    }

    }

    相关文章

      网友评论

          本文标题:深拷贝浅拷贝

          本文链接:https://www.haomeiwen.com/subject/cngxjttx.html