问题:
1.copy与mutablecopy的区别是什么
2.copy与strong的区别是什么
3.不可变对象(如NSString)用copy修饰还是strong修饰,
可变对象(如NSMutableString)用copy修饰还是strong修饰
copy、mutablecopy、strong这三个概念早就接触了,但是理解的一直都不深刻,现在,有必要重新整理一下。
答案:
1.copy:对不可变对象copy是浅拷贝,对可变对象copy是深拷贝
mutableCopy:一定是深拷贝
深拷贝时,copy出的是不可变类型,mutablecopy出的是可变类型
2.copy会开辟新内存复制一份新的数据,strong只是对象的引用计数加1
3.不可变对象用copy修饰,可变对象用strong修饰
另外:要实现自定义对象copy,需遵守NSCopying、NSMutableCopying协议,实现copyWithZone、mutableCopyWithZone 方法
是不是有点晕了,下面举个例子分析一下:
NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"a", @"b", nil];
[arr addObject:@"!"];
NSLog(@"%@ ----- %@ ----- %@", [arr class], [[arr copy] class], [[arr mutableCopy] class]);
NSLog(@"%p ==== %p ==== %p",arr, [arr copy], [arr mutableCopy]);
NSArray *arr2 = [NSArray arrayWithObjects:@"a", @"b", nil];
NSLog(@"%@ ----- %@ ----- %@", [arr2 class], [[arr2 copy] class], [[arr2 mutableCopy] class]);
NSLog(@"%p ==== %p ==== %p",arr2, [arr2 copy], [arr2 mutableCopy]);
2018-04-23 11:59:21.922827+0800 iyuba[2204:86964] __NSArrayM ----- __NSArrayI ----- __NSArrayM
2018-04-23 11:59:21.922945+0800 iyuba[2204:86964] 0x604000447ce0 ==== 0x6040004400f0 ==== 0x60400025fbf0
2018-04-23 11:59:21.923060+0800 iyuba[2204:86964] __NSArrayI ----- __NSArrayI ----- __NSArrayM
2018-04-23 11:59:21.923375+0800 iyuba[2204:86964] 0x604000432860 ==== 0x604000432860 ==== 0x6040004400f0
第一行:可变对象copy后生成的是不可变类型,mutablecopy后生成的是可变类型
第二行:可变对象copy后产生了新的对象,mutablecopy后产生了新的对象
第三行:不可变对象copy后还是不可变类型,mutablecopy后生成的是可变类型
第四行:不可变对象copy后没有产生新的对象,mutablecopy后产生新的对象
总结一:可变对象copy产生新对象(深拷贝),对象是不可变类型,mutablecopy产生新对象(深拷贝),对象是可变类型;不可变对象copy没有产生新对象(浅拷贝),mutablecopy产生新对象(深拷贝),对象是可变类型。
是不是对应了上边的答案呢。下面来看用copy与strong修饰对象时的区别:
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end
Person *person = [[Person alloc] init];
person.name = string;
[string appendString:@"--修改过的名字"];
NSLog(@"name = %@", person.name);
NSLog(@"%p ----- %p", string, person.name);
2018-04-23 11:59:21.923686+0800 iyuba[2204:86964] name = 我是名字
2018-04-23 11:59:21.923851+0800 iyuba[2204:86964] 0x6040004400f0 ----- 0x6040004323c0
实际赋值是这样的
- (void)setName:(NSString *)name
{
_name = [name copy];
}
从上面的结论可以得到,copy不论深浅拷贝,结果一定是不可变的,所以name值是不会变的。
但是若用strong修饰name
@property (nonatomic, strong) NSString *name;
2018-04-23 12:09:53.585089+0800 iyuba[2323:93298] name = 我是名字--修改过的名字
name时会跟着变化的,原因是strong是强引用,使name成为一个指针指向了string对象。
总结二:strong使我们定义的NSString类型产生了不可控制的结果,所以对于不可变类型需要用copy来修饰。
同样的对于可变类型为什么用strong修饰呢,我们只需要看copy修饰会出现什么情况
@property (nonatomic, copy) NSMutableString *name;
NSMutableString *string = [NSMutableString stringWithFormat:@"我是名字"];
Person *person = [[Person alloc] init];
person.name = string;
[person.name appendString:@"--修改过的名字"];
NSLog(@"name = %@", person.name);
NSLog(@"%p ----- %p", string, person.name);
运行之后就会发现appendString崩溃,原因就是copy返回的是不可变的类型,所以是不能修改值的。
总结三:可变对象需要用strong修饰。