iOS中的Copy

iOS提供了copy与mutableCopy方法,copy就是复制了一个不可变的对象,而mutableCopy就是复制了一个可变的对象,下面通过几个实例来演示一下。

一、非容器类对象的copy与mutableCopy

    NSString *str = [NSString stringWithFormat:@"%@", @"create by "];
    NSLog(@"str: %p 值:%@ 引用计数:%lu", str, str, [str retainCount]);

    NSString *strCopy = [str copy];
    NSLog(@"strCopy: %p 值:%@ 引用计数:%lu", strCopy, strCopy, [strCopy retainCount]);

    NSMutableString *mStrCopy = [str mutableCopy];
    NSLog(@"mStrCopy: %p 值:%@ 引用计数:%lu", mStrCopy, mStrCopy, [mStrCopy retainCount]);

    NSMutableString *mStrCopy2 = [mStrCopy copy];
    NSLog(@"mStrCopy2:%p 值:%@ 引用计数:%lu", mStrCopy2, mStrCopy2, [mStrCopy2 retainCount]);
    //下面一句代码不注释则引起crash
//    [mStrCopy2 appendString:@"xiangpuhua"];
//    NSLog(@"mStrCopy2:%p 值:%@ 引用计数:%lu", mStrCopy2, mStrCopy2, [mStrCopy2 retainCount]);

    [mStrCopy appendString:@"xiangpuhua"];
    NSLog(@"mStrCopy:%p 值:%@ 引用计数:%lu", mStrCopy, mStrCopy, [mStrCopy retainCount]);

    NSMutableString *mStrCopy3 = [mStrCopy mutableCopy];
    NSLog(@"mStrCopy3:%p 值:%@ 引用计数:%lu", mStrCopy3, mStrCopy3, [mStrCopy3 retainCount]);
    [mStrCopy3 appendString:@"!!!"];
    NSLog(@"mStrCopy3:%p 值:%@ 引用计数:%lu", mStrCopy3, mStrCopy3, [mStrCopy3 retainCount]);

输出结果:

2017-02-27 17:49:42.859 CopyTest[12206:2131173] str: 0x60000002ade0 值:create by  引用计数:1
2017-02-27 17:49:42.859 CopyTest[12206:2131173] strCopy: 0x60000002ade0 值:create by  引用计数:2
2017-02-27 17:49:42.860 CopyTest[12206:2131173] mStrCopy: 0x600000074940 值:create by  引用计数:1
2017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy2:0x60000002ae20 值:create by  引用计数:1
2017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy:0x600000074940 值:create by xiangpuhua 引用计数:1
2017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy3:0x600000074a40 值:create by xiangpuhua 引用计数:1
2017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy3:0x600000074a40 值:create by xiangpuhua!!! 引用计数:1

由输出结果,我们可知,str与strCopy指向同一内存区域,此时str与strCopy的引用计数一样都为2。而mStrCopy则是真正意义上的复制,系统为其分配了新的内存,但指针所指向的字符串还是和str所指的一样。而对mStrCopy进行copy的时候发现mStrCopy2与mStrCopy指向不是同一个指针,说明也是进行了真正意义上的复制,由此我们可以得出以下结论:
1、对不可变对象复制,copy是指针复制(浅拷贝),而mutableCopy是对象复制(深拷贝)
2、对可变对象复制,copy与mutableCopy都是对象复制(深拷贝)。
3、对可变对象复制,copy出来的对象是不可变的。

二、容器类对象的copy与mutableCopy

容器类对象指的是NSArray、NSDictionary等。

    NSArray *arr = @[@"a"];
    NSLog(@"arr: %p 值:%@ 引用计数:%lu", arr, arr, [arr retainCount]);

    NSArray *arrCopy = [arr copy];
    NSLog(@"arrCopy: %p 值:%@ 引用计数:%lu", arrCopy, arrCopy, [arrCopy retainCount]);

    NSMutableArray *mArrCopy = [arr mutableCopy];
    NSLog(@"mArrCopy: %p 值:%@ 引用计数:%lu", mArrCopy, mArrCopy, [mArrCopy retainCount]);

    NSMutableArray *mArrCopy2 = [mArrCopy copy];
    NSLog(@"mArrCopy2:%p 值:%@ 引用计数:%lu", mArrCopy2, mArrCopy2, [mArrCopy2 retainCount]);
    //下面一句代码不注释则引起crash
//    [mArrCopy2 addObject:@"b"];
//    NSLog(@"mArrCopy2:%p 值:%@ 引用计数:%lu", mArrCopy2, mArrCopy2, [mArrCopy2 retainCount]);

    [mArrCopy addObject:@"c"];
    NSLog(@"mArrCopy:%p 值:%@ 引用计数:%lu", mArrCopy, mArrCopy, [mArrCopy retainCount]);

    NSMutableArray *mArrCopy3 = [mArrCopy mutableCopy];
    NSLog(@"mArrCopy3:%p 值:%@ 引用计数:%lu", mArrCopy3, mArrCopy3, [mArrCopy3 retainCount]);
    [mArrCopy3 addObject:@"d"];
    NSLog(@"mArrCopy3:%p 值:%@ 引用计数:%lu", mArrCopy3, mArrCopy3, [mArrCopy3 retainCount]);

输出结果:

2017-02-27 18:01:32.190 ffm[12459:2216832] arr: 0x60000001d6d0 值:(
    a
) 引用计数:1
2017-02-27 18:01:32.190 ffm[12459:2216832] arrCopy: 0x60000001d6d0 值:(
    a
) 引用计数:2
2017-02-27 18:01:32.191 ffm[12459:2216832] mArrCopy: 0x600000248940 值:(
    a
) 引用计数:1
2017-02-27 18:01:32.191 ffm[12459:2216832] mArrCopy2:0x60800001d360 值:(
    a
) 引用计数:1
2017-02-27 18:01:32.191 ffm[12459:2216832] mArrCopy:0x600000248940 值:(
    a,
    c
) 引用计数:1
2017-02-27 18:01:32.192 ffm[12459:2216832] mArrCopy3:0x608000242dc0 值:(
    a,
    c
) 引用计数:1
2017-02-27 18:01:32.192 ffm[12459:2216832] mArrCopy3:0x608000242dc0 值:(
    a,
    c,
    d
) 引用计数:1

由输出结果可知:容器类基本规则与非容器类一致,遵循一下规则
1、对不可变对象复制,copy是指针复制(浅拷贝),而mutableCopy是对象复制(深拷贝)
2、对可变对象复制,copy与mutableCopy都是对象复制(深拷贝)。
3、对可变对象复制,copy出来的对象是不可变的。
但是我们需要研究的是复制后容器内对象的变化。

    NSArray *arr = @[[NSMutableString stringWithString:@"create by "], [NSString stringWithFormat:@"%@", @"xph"]];
    NSLog(@"arr: %p 值:%@ 引用计数:%lu", arr, arr, [arr retainCount]);
    for (int i=0; i<arr.count; i++) {
        id object = arr[i];
        NSLog(@"arr中第%d个元素: %p 值:%@ 引用计数:%lu", i, object, object, [object retainCount]);
    }

    NSArray *arrCopy = [arr copy];
    NSLog(@"arrCopy: %p 值:%@ 引用计数:%lu", arrCopy, arrCopy, [arrCopy retainCount]);
    for (int i=0; i<arrCopy.count; i++) {
        id object = arrCopy[i];
        NSLog(@"arrCopy中第%d个元素: %p 值:%@ 引用计数:%lu", i, object, object, [object retainCount]);
    }

    NSMutableArray *mArrCopy = [arr mutableCopy];
    NSLog(@"mArrCopy: %p 值:%@ 引用计数:%lu", mArrCopy, mArrCopy, [mArrCopy retainCount]);
    for (int i=0; i<mArrCopy.count; i++) {
        id object = mArrCopy[i];
        NSLog(@"mArrCopy中第%d个元素: %p 值:%@ 引用计数:%lu", i, object, object, [object retainCount]);
    }

    NSMutableString *first = mArrCopy[0];
    [first appendString:@"xiangpuhua"];

    NSLog(@"arr: %p 值:%@ 引用计数:%lu", arr, arr, [arr retainCount]);
    for (int i=0; i<arr.count; i++) {
        id object = arr[i];
        NSLog(@"arr中第%d个元素: %p 值:%@ 引用计数:%lu", i, object, object, [object retainCount]);
    }

输出结果:

2017-02-27 18:13:49.963 CopyTest[12598:2286314] arr: 0x6080002281a0 值:(
    "create by ",
    xph
) 引用计数:1
2017-02-27 18:13:49.963 CopyTest[12598:2286314] arr中第0个元素: 0x608000273680 值:create by  引用计数:2
2017-02-27 18:13:49.963 CopyTest[12598:2286314] arr中第1个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 18:13:49.964 CopyTest[12598:2286314] arrCopy: 0x6080002281a0 值:(
    "create by ",
    xph
) 引用计数:2
2017-02-27 18:13:49.964 CopyTest[12598:2286314] arrCopy中第0个元素: 0x608000273680 值:create by  引用计数:2
2017-02-27 18:13:49.964 CopyTest[12598:2286314] arrCopy中第1个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 18:13:49.964 CopyTest[12598:2286314] mArrCopy: 0x60800024c4e0 值:(
    "create by ",
    xph
) 引用计数:1
2017-02-27 18:13:49.965 CopyTest[12598:2286314] mArrCopy中第0个元素: 0x608000273680 值:create by  引用计数:3
2017-02-27 18:13:49.965 CopyTest[12598:2286314] mArrCopy中第1个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 18:13:49.965 CopyTest[12598:2286314] arr: 0x6080002281a0 值:(
    "create by xiangpuhua",
    xph
) 引用计数:2
2017-02-27 18:13:49.965 CopyTest[12598:2286314] arr中第0个元素: 0x608000273680 值:create by xiangpuhua 引用计数:3
2017-02-27 18:13:49.967 CopyTest[12598:2286314] arr中第1个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615

由此可知:不管是copy还是mutableCopy,容器内元素只是实现了指针的复制(浅拷贝)。
如果要实现容器内的元素也是深拷贝,怎么办呢?

NSArray *arr = @[@[[NSMutableString stringWithString:@"create by "]].mutableCopy, [NSMutableString stringWithString:@"iOS "], [NSString stringWithFormat:@"%@", @"xph"]];
    NSArray *deepCopyArray = [[NSArray alloc] initWithArray:arr copyItems:YES];
    NSArray *deepCopyArray2 = [NSKeyedUnarchiver unarchiveObjectWithData:
                                  [NSKeyedArchiver archivedDataWithRootObject:arr]];
    NSLog(@"1: %p 值:%@ 引用计数:%lu", arr, arr, [arr retainCount]);
    NSLog(@"2: %p 值:%@ 引用计数:%lu", deepCopyArray, deepCopyArray, [deepCopyArray retainCount]);
    NSLog(@"3: %p 值:%@ 引用计数:%lu", deepCopyArray2, deepCopyArray2, [deepCopyArray2 retainCount]);
    for (int i=0; i<arr.count; i++) {
        id o1 = arr[i];
        id o2 = deepCopyArray[i];
        id o3 = deepCopyArray2[i];
        NSLog(@"1、中第%d个元素: %p 值:%@ 引用计数:%lu", i, o1, o1, [o1 retainCount]);
        NSLog(@"2、中第%d个元素: %p 值:%@ 引用计数:%lu", i, o2, o2, [o2 retainCount]);
        NSLog(@"3、中第%d个元素: %p 值:%@ 引用计数:%lu", i, o3, o3, [o3 retainCount]);
        if ([o1 isKindOfClass:[NSArray class]]) {
            for (id oo in o1) {
                NSLog(@"1、子元素: %p 值:%@ 引用计数:%lu", oo, oo, [oo retainCount]);
            }
        }
        if ([o2 isKindOfClass:[NSArray class]]) {
            for (id oo in o2) {
                NSLog(@"2、子元素: %p 值:%@ 引用计数:%lu", oo, oo, [oo retainCount]);
            }
        }
        if ([o3 isKindOfClass:[NSArray class]]) {
            for (id oo in o3) {
                NSLog(@"3、子元素: %p 值:%@ 引用计数:%lu", oo, oo, [oo retainCount]);
            }
        }
    }

输出结果:

2017-02-27 22:20:00.628 CopyTest[14436:3967892] 1: 0x60000005d010 值:(
        (
        "create by "
    ),
    "iOS ",
    xph
) 引用计数:1
2017-02-27 22:20:00.628 CopyTest[14436:3967892] 2: 0x60000005d040 值:(
        (
        "create by "
    ),
    "iOS ",
    xph
) 引用计数:1
2017-02-27 22:20:00.628 CopyTest[14436:3967892] 3: 0x60000005d490 值:(
        (
        "create by "
    ),
    "iOS ",
    xph
) 引用计数:1
2017-02-27 22:20:00.628 CopyTest[14436:3967892] 1、中第0个元素: 0x60000005cfe0 值:(
    "create by "
) 引用计数:2
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 2、中第0个元素: 0x60000000afd0 值:(
    "create by "
) 引用计数:1
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 3、中第0个元素: 0x60000005d2e0 值:(
    "create by "
) 引用计数:1
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 1、子元素: 0x600000077700 值:create by  引用计数:4
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 2、子元素: 0x600000077700 值:create by  引用计数:4
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 3、子元素: 0x600000077ac0 值:create by  引用计数:1
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 1、中第1个元素: 0x600000077780 值:iOS  引用计数:2
2017-02-27 22:20:00.630 CopyTest[14436:3967892] 2、中第1个元素: 0xa00000020534f694 值:iOS  引用计数:18446744073709551615
2017-02-27 22:20:00.631 CopyTest[14436:3967892] 3、中第1个元素: 0x600000077b80 值:iOS  引用计数:1
2017-02-27 22:20:00.631 CopyTest[14436:3967892] 1、中第2个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 22:20:00.631 CopyTest[14436:3967892] 2、中第2个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 22:20:00.631 CopyTest[14436:3967892] 3、中第2个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615

根据输出结果我们可知,deepCopyArray实现了一层的深拷贝,也就是说deepCopyArray实现了其内第一层元素(即数组的直接元素)的深拷贝,当数组中的元素为容器类元素时,无法实现第二层数据的深拷贝,而deepCopyArray2实现了真正的深拷贝。(官网解释

总结如下:
1、对不可变对象复制,copy是指针复制(浅拷贝),而mutableCopy是对象复制(深拷贝)
2、对可变对象复制,copy与mutableCopy都是对象复制(深拷贝)。
3、对可变对象复制,copy出来的对象是不可变的。
4、容器类对象copy与mutableCopy时,元素均为指针复制(浅拷贝)。
5、使用initWithArray:copyItems:且第二个参数为YES的时候实现了一层的深拷贝
6、容器类对象中的元素不可变时,对象复制(深拷贝)并没有真正拷贝对象,而是指针的拷贝。

三、copy关键字

(1)NSString、NSArray、NSDictionay等经常使用copy关键字。
原因:因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的属性不受外界影响,使用copy无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本,如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。

//User.h文件中

@property (nonatomic, strong) NSString *name;//此时若将一个可变字符串set给name,那么此时的name则指向的是一个可变字符,那么就无法保证name的不可变性   
@property (nonatomic, copy) NSString *name;//此时若将一个可变字符串set给name,此时会执行[MutableString copy]内容复制,即深复制,将返回一个不可变字符串,即name指向的是一个不可变字符串,以后即使MutableString改变也不会影响name的值           
  例如:
NSMutableString *string = [NSMutableString stringWithString:@"origin"];//copy
NSString *stringCopy = [string copy];
[string appendString:@"origion!"]

此时的打印结果:string:originorigion!,而stringCopy仍为:origin
(2)block也经常会使用copy关键字
原因:block使用copy是从MRC遗留下来的“传统”,在MRC中,方法内部的block是在栈区的,使用copy可以把它放到堆区。在ARC中写不写都行。对于block使用copy还是strong效果是一样的,但写上copy也无伤大雅,还能时刻提醒我们:编译器自动对block进行了copy操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值