首页 > 系统 > iOS > 正文

iOS中的Copy

2019-11-06 09:54:54
字体:
来源:转载
供稿:网友

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操作。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表