iOS中的Copy

来源:互联网 发布:美国经济数据gdp 编辑:程序博客网 时间:2024/05/01 07:47

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  引用计数:12017-02-27 17:49:42.859 CopyTest[12206:2131173] strCopy: 0x60000002ade0 值:create by  引用计数:22017-02-27 17:49:42.860 CopyTest[12206:2131173] mStrCopy: 0x600000074940 值:create by  引用计数:12017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy2:0x60000002ae20 值:create by  引用计数:12017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy:0x600000074940 值:create by xiangpuhua 引用计数:12017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy3:0x600000074a40 值:create by xiangpuhua 引用计数:12017-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) 引用计数:12017-02-27 18:01:32.190 ffm[12459:2216832] arrCopy: 0x60000001d6d0 值:(    a) 引用计数:22017-02-27 18:01:32.191 ffm[12459:2216832] mArrCopy: 0x600000248940 值:(    a) 引用计数:12017-02-27 18:01:32.191 ffm[12459:2216832] mArrCopy2:0x60800001d360 值:(    a) 引用计数:12017-02-27 18:01:32.191 ffm[12459:2216832] mArrCopy:0x600000248940 值:(    a,    c) 引用计数:12017-02-27 18:01:32.192 ffm[12459:2216832] mArrCopy3:0x608000242dc0 值:(    a,    c) 引用计数:12017-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) 引用计数:12017-02-27 18:13:49.963 CopyTest[12598:2286314] arr中第0个元素: 0x608000273680 值:create by  引用计数:22017-02-27 18:13:49.963 CopyTest[12598:2286314] arr中第1个元素: 0xa000000006870783 值:xph 引用计数:184467440737095516152017-02-27 18:13:49.964 CopyTest[12598:2286314] arrCopy: 0x6080002281a0 值:(    "create by ",    xph) 引用计数:22017-02-27 18:13:49.964 CopyTest[12598:2286314] arrCopy中第0个元素: 0x608000273680 值:create by  引用计数:22017-02-27 18:13:49.964 CopyTest[12598:2286314] arrCopy中第1个元素: 0xa000000006870783 值:xph 引用计数:184467440737095516152017-02-27 18:13:49.964 CopyTest[12598:2286314] mArrCopy: 0x60800024c4e0 值:(    "create by ",    xph) 引用计数:12017-02-27 18:13:49.965 CopyTest[12598:2286314] mArrCopy中第0个元素: 0x608000273680 值:create by  引用计数:32017-02-27 18:13:49.965 CopyTest[12598:2286314] mArrCopy中第1个元素: 0xa000000006870783 值:xph 引用计数:184467440737095516152017-02-27 18:13:49.965 CopyTest[12598:2286314] arr: 0x6080002281a0 值:(    "create by xiangpuhua",    xph) 引用计数:22017-02-27 18:13:49.965 CopyTest[12598:2286314] arr中第0个元素: 0x608000273680 值:create by xiangpuhua 引用计数:32017-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) 引用计数:12017-02-27 22:20:00.628 CopyTest[14436:3967892] 2: 0x60000005d040 值:(        (        "create by "    ),    "iOS ",    xph) 引用计数:12017-02-27 22:20:00.628 CopyTest[14436:3967892] 3: 0x60000005d490 值:(        (        "create by "    ),    "iOS ",    xph) 引用计数:12017-02-27 22:20:00.628 CopyTest[14436:3967892] 1、中第0个元素: 0x60000005cfe0 值:(    "create by ") 引用计数:22017-02-27 22:20:00.629 CopyTest[14436:3967892] 2、中第0个元素: 0x60000000afd0 值:(    "create by ") 引用计数:12017-02-27 22:20:00.629 CopyTest[14436:3967892] 3、中第0个元素: 0x60000005d2e0 值:(    "create by ") 引用计数:12017-02-27 22:20:00.629 CopyTest[14436:3967892] 1、子元素: 0x600000077700 值:create by  引用计数:42017-02-27 22:20:00.629 CopyTest[14436:3967892] 2、子元素: 0x600000077700 值:create by  引用计数:42017-02-27 22:20:00.629 CopyTest[14436:3967892] 3、子元素: 0x600000077ac0 值:create by  引用计数:12017-02-27 22:20:00.629 CopyTest[14436:3967892] 1、中第1个元素: 0x600000077780 值:iOS  引用计数:22017-02-27 22:20:00.630 CopyTest[14436:3967892] 2、中第1个元素: 0xa00000020534f694 值:iOS  引用计数:184467440737095516152017-02-27 22:20:00.631 CopyTest[14436:3967892] 3、中第1个元素: 0x600000077b80 值:iOS  引用计数:12017-02-27 22:20:00.631 CopyTest[14436:3967892] 1、中第2个元素: 0xa000000006870783 值:xph 引用计数:184467440737095516152017-02-27 22:20:00.631 CopyTest[14436:3967892] 2、中第2个元素: 0xa000000006870783 值:xph 引用计数:184467440737095516152017-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"];//copyNSString *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
原创粉丝点击