iOS Copy

作者: 孔朝阳 | 来源:发表于2019-12-19 10:39 被阅读0次

    一、拷贝对象的基本概念

    拷贝一个对象的副本,开辟一块新的内存来存储副本对象

    二、浅拷贝和深拷贝

    1、浅拷贝

    浅拷贝就是对对象内存地址的拷贝,让目标指针和源指针指向同一片内存空间。
    浅拷贝只是对对象的简单拷贝,让几个指针共用一片内存,当内存销毁的时候,指向这片内存的几个指针需要重新定义才可以使用,不然会成为野指针。
    在iOS中,使用retain,是一种更加保险的浅拷贝。它让几个指针共用同一块内存空间。 由于引用计数的存在,不会轻易的销毁内存,达到更加简单使用的目的。

    2、深拷贝

    深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。

    三、协议

    如果一个对象想具备拷贝的功能,必须实现协议。
    NSObject自带的常用的对象有:NSNumber、NSString、NSArray、NSDictionary、NSMutableString、NSMutableArray、NSMutableDictionary
    iOS提供了copy和mutableCopy方法,顾名思义,copy就是复制了一个imutable的对象,而mutableCopy就是复制了一个mutable的对象。
    当然在iOS中并不是所有的对象都支持copy和mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutableCopying 协议的类才可以发送mutableCopy消息。假如发送了一个没有遵守上述两协议而发送copy或者mutableCopy,那么就会发生异常。但是默认的iOS类并没有遵守这两个协议。如果想自定义copy就必须遵守NSCopying,并且实现copyWithZone:方法,如果想自定义mutableCopy就必须遵守NSMutableCopying,并且实现mutableCopyWithZone:方法。

    四、copy和retain的区别

    copy是创建一个对象,retain是创建一个指针。
    copy属性表示两个对象内容相同,新的对象引用计数为1 ,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。
    retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的引用计数+1。
    也就是说,retain 是指针拷贝(浅拷贝),copy 是对象拷贝(深拷贝)。

    五、探究

    #define MyLog(Comment, Obj) NSLog(@"注释:%@_指针地址:%p_对象地址:%p_对象:%@_引用计数:%ld", Comment, &Obj, Obj, Obj, [Obj retainCount]);
    

    1、系统的非容器类对象

    (NSString,NSNumber等一类的对象)

    1.1、不可变对象

    NSString *string = @"Hello";
    MyLog(@"String", string);
    NSString *copyString = [string copy];
    MyLog(@"CopyString", copyString);
    NSString *mutableCopyString = [string mutableCopy];
    MyLog(@"MutableCopyString", mutableCopyString);
        
    string = @"World";
    MyLog(@"String", string);
    MyLog(@"CopyString", copyString);
    MyLog(@"MutableCopyString", mutableCopyString);
    
    2019-12-17 14:13:05.888336+0800 CopyTest[5239:233232] 注释:String_指针地址:0x7ffeee082a38_对象地址:0x101b7c050_对象:Hello_引用计数:-1
    2019-12-17 14:13:07.112412+0800 CopyTest[5239:233232] 注释:CopyString_指针地址:0x7ffeee082a30_对象地址:0x101b7c050_对象:Hello_引用计数:-1
    2019-12-17 14:13:10.228491+0800 CopyTest[5239:233232] 注释:MutableCopyString_指针地址:0x7ffeee082a28_对象地址:0x600003558990_对象:Hello_引用计数:1
    2019-12-17 14:13:16.821985+0800 CopyTest[5239:233232] 注释:String_指针地址:0x7ffeee082a38_对象地址:0x101b7c0f0_对象:World_引用计数:-1
    2019-12-17 14:13:25.889237+0800 CopyTest[5239:233232] 注释:CopyString_指针地址:0x7ffeee082a30_对象地址:0x101b7c050_对象:Hello_引用计数:-1
    2019-12-17 14:13:58.920537+0800 CopyTest[5239:233232] 注释:MutableCopyString_指针地址:0x7ffeee082a28_对象地址:0x600003558990_对象:Hello_引用计数:1
    

    查看Log可发现,string和copyString指向的是同一块内存区域。而mutableCopyString则是我们所说的真正意义上的拷贝,系统为其分配了新内存,引用计数为1,指针所指向的字符串内容和string所指的一样。

    1.2、可变对象

    NSMutableString *mutableString = [NSMutableString stringWithFormat:@"Hello"];
    MyLog(@"MutableString", mutableString);
    NSString *copyMutableString = [mutableString copy];
    MyLog(@"CopyMutableString", copyMutableString);
    NSString *mutableCopyMutableString = [mutableString mutableCopy];
    MyLog(@"MutableCopyMutableString", mutableCopyMutableString);
        
    mutableString = [NSMutableString stringWithFormat:@"World"];
    MyLog(@"MutableString", mutableString);
    MyLog(@"CopyMutableString", copyMutableString);
    MyLog(@"MutableCopyMutableString", mutableCopyMutableString);
    
    2019-12-17 14:22:47.659570+0800 CopyTest[5512:258797] 注释:MutableString_指针地址:0x7ffee358ea38_对象地址:0x600002204c00_对象:Hello_引用计数:1
    2019-12-17 14:22:49.269361+0800 CopyTest[5512:258797] 注释:CopyMutableString_指针地址:0x7ffee358ea30_对象地址:0x8d16218c3feb7c2b_对象:Hello_引用计数:-1
    2019-12-17 14:22:53.712337+0800 CopyTest[5512:258797] 注释:MutableCopyMutableString_指针地址:0x7ffee358ea28_对象地址:0x600002254000_对象:Hello_引用计数:1
    2019-12-17 14:22:58.449147+0800 CopyTest[5512:258797] 注释:MutableString_指针地址:0x7ffee358ea38_对象地址:0x600002204ab0_对象:World_引用计数:1
    2019-12-17 14:23:06.121620+0800 CopyTest[5512:258797] 注释:CopyMutableString_指针地址:0x7ffee358ea30_对象地址:0x8d16218c3feb7c2b_对象:Hello_引用计数:-1
    2019-12-17 14:23:09.417593+0800 CopyTest[5512:258797] 注释:MutableCopyMutableString_指针地址:0x7ffee358ea28_对象地址:0x600002254000_对象:Hello_引用计数:1
    

    copy产生的对象是不可变的,mutableCopy产生的对象是可变的
    对于系统的非容器类对象,我们可以认为,如果对一不可变对象拷贝,copy是指针拷贝(浅拷贝),mutableCopy就是对象拷贝(深拷贝)。如果是对可变对象拷贝,都是深拷贝,但是copy返回的对象是不可变的。

    2、系统的容器类对象

    (NSArray,NSDictionary等一类的对象, 对于容器类本身,上面讨论的结论也是适用的,需要探讨的是拷贝后容器内对象的变化。)

    2.1、不可变对象

    NSObject *object = [[NSObject alloc] init];
    NSArray *array = @[object];
    MyLog(@"Array", array);
    NSArray *copyArray = [array copy];
    MyLog(@"CopyArray", copyArray);
    NSMutableArray *mutableCopyArray = [array mutableCopy];
    MyLog(@"MutableCopyArray", mutableCopyArray);
        
    array = @[object, object];
    MyLog(@"Array", array);
    MyLog(@"CopyArray", copyArray);
    MyLog(@"MutableCopyArray", mutableCopyArray);
    
    2019-12-17 14:48:05.654817+0800 CopyTest[6223:303565] 注释:Array_指针地址:0x7ffeee88ca10_对象地址:0x600001384c60_对象:(
        "<NSObject: 0x600001384c50>"
    )_引用计数:1
    2019-12-17 14:48:05.655102+0800 CopyTest[6223:303565] 注释:CopyArray_指针地址:0x7ffeee88ca08_对象地址:0x600001384c60_对象:(
        "<NSObject: 0x600001384c50>"
    )_引用计数:2
    2019-12-17 14:48:05.655236+0800 CopyTest[6223:303565] 注释:MutableCopyArray_指针地址:0x7ffeee88ca00_对象地址:0x600001fc5b60_对象:(
        "<NSObject: 0x600001384c50>"
    )_引用计数:1
    2019-12-17 14:48:05.655349+0800 CopyTest[6223:303565] 注释:Array_指针地址:0x7ffeee88ca10_对象地址:0x600001191dc0_对象:(
        "<NSObject: 0x600001384c50>",
        "<NSObject: 0x600001384c50>"
    )_引用计数:1
    2019-12-17 14:48:05.655451+0800 CopyTest[6223:303565] 注释:CopyArray_指针地址:0x7ffeee88ca08_对象地址:0x600001384c60_对象:(
        "<NSObject: 0x600001384c50>"
    )_引用计数:2
    2019-12-17 14:48:05.655525+0800 CopyTest[6223:303565] 注释:MutableCopyArray_指针地址:0x7ffeee88ca00_对象地址:0x600001fc5b60_对象:(
        "<NSObject: 0x600001384c50>"
    )_引用计数:1
    

    copyArray是指针拷贝,而mutableCopyArray是对象拷贝,mutableCopyArray还可以改变内部的元素:删除或添加。但是注意的是,容器内的元素内容都是指针拷贝。

    2.2、可变对象

    NSObject *object = [[NSObject alloc] init];
    NSMutableArray *mutableArray = [NSMutableArray arrayWithObject:object];
    MyLog(@"MutableArray", mutableArray);
    NSArray *copyMutableArray = [mutableArray copy];
    MyLog(@"CopyMutableArray", copyMutableArray);
    NSMutableArray *mutableCopyMutableArray = [mutableArray mutableCopy];
    MyLog(@"MutableCopyMutableArray", mutableCopyMutableArray);
        
    [mutableArray addObject:object];
    MyLog(@"MutableArray", mutableArray);
    MyLog(@"CopyMutableArray", copyMutableArray);
    MyLog(@"MutableCopyArray", mutableCopyMutableArray);
    
    2019-12-17 14:53:20.011397+0800 CopyTest[6368:322462] 注释:MutableArray_指针地址:0x7ffeed6b5a30_对象地址:0x6000021f9f20_对象:(
        "<NSObject: 0x600002da7700>"
    )_引用计数:1
    2019-12-17 14:53:26.402298+0800 CopyTest[6368:322462] 注释:CopyMutableArray_指针地址:0x7ffeed6b5a28_对象地址:0x600002da7710_对象:(
        "<NSObject: 0x600002da7700>"
    )_引用计数:1
    2019-12-17 14:53:35.683280+0800 CopyTest[6368:322462] 注释:MutableCopyMutableArray_指针地址:0x7ffeed6b5a20_对象地址:0x6000021e61f0_对象:(
        "<NSObject: 0x600002da7700>"
    )_引用计数:1
    2019-12-17 14:53:40.723298+0800 CopyTest[6368:322462] 注释:MutableArray_指针地址:0x7ffeed6b5a30_对象地址:0x6000021f9f20_对象:(
        "<NSObject: 0x600002da7700>",
        "<NSObject: 0x600002da7700>"
    )_引用计数:1
    2019-12-17 14:53:47.418461+0800 CopyTest[6368:322462] 注释:CopyMutableArray_指针地址:0x7ffeed6b5a28_对象地址:0x600002da7710_对象:(
        "<NSObject: 0x600002da7700>"
    )_引用计数:1
    2019-12-17 14:53:50.173948+0800 CopyTest[6368:322462] 注释:MutableCopyArray_指针地址:0x7ffeed6b5a20_对象地址:0x6000021e61f0_对象:(
        "<NSObject: 0x600002da7700>"
    )_引用计数:1
    

    由此可见,对于容器而言,其元素对象始终是指针拷贝。如果需要元素对象也是对象拷贝,就需要自己实现深拷贝。

    相关文章

      网友评论

          本文标题:iOS Copy

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