@property 声明的NSString为何要使用copy来修饰?如果用strong,会发生什么?
-
因为父类指针可以指向子类对象,使用拷贝的目的是为了让本对象的属性不受外界影响,使用拷贝无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。
-
如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
- (void)someFunctionWithArray:(NSArray *)array { self.array = array; } - (void)viewDidLoad { [super viewDidLoad]; NSMutableArray *mutableArray = [NSMutableArray new]; [mutableArray addObject:@"20"]; [self someFunctionWithArray:mutableArray]; NSLog(@"count = %@", self.array); [mutableArray addObject:@"40"]; NSLog(@"count = %@", self.array); }
打印结果如下:
2017-12-05 20:09:02.862459+0800 TestDemo[4435:1823871] count = (
20
)
2017-12-05 20:09:02.862656+0800 TestDemo[4435:1823871] count = (
20,
40
)
如果将strong改为copy, 打印结果如下:
2017-12-05 20:13:37.365180+0800 TestDemo[4471:1860623] count = (
20
)
2017-12-05 20:13:37.365383+0800 TestDemo[4471:1860623] count = (
20
)
引申另外一个问题:如果声明NSMutableArray等可变对象使用copy修饰,会有什么问题?
NSArray *array = @[@"1", @"2", @"3", @"4"];
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array];
self.mutableArray = mutableArray;
[self.mutableArray addObject:@"20"];
会出现以下Crash:
2017-12-05 21:08:24.756887+0800 TestDemo[4844:2215665] -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x600000246090
使用copy修饰可变对象,在进行赋值的时候,是使用copy方法的。而此时self.mutableArray得到的实际上是一个不可变数组。当你对数组进行增删操作时,会crash。
非集合类对象的copy和mutableCopy
NSMutableString *string = [NSMutableString stringWithString:@"MutableString"];
// 可变对象的copy, 指向不同地址
NSString *stringCopy = [string copy];
// 不可变字符串copy,指向的是同一个地址
NSString *stringCopy2 = [stringCopy copy];
// 不可变字符串的mutableCopy,指向的是不同的地址
NSMutableString *mutableCopy = [stringCopy mutableCopy];
// 可变字符串的mutableCopy,指向的是不同的地址
NSMutableString *mutableCopy2 = [string mutableCopy];
NSLog(@"MutableString = %p", string);
NSLog(@"stringCopy = %p", stringCopy);
NSLog(@"stringCopy2 = %p", stringCopy2);
NSLog(@"mutableCopy = %p", mutableCopy);
NSLog(@"mutableCopy2 = %p", mutableCopy2);
打印输出如下:
2017-12-05 20:27:17.194786+0800 TestDemo[4647:1943709] MutableString = 0x60400025a5b0
2017-12-05 20:27:17.194951+0800 TestDemo[4647:1943709] stringCopy = 0x6040000367e0
2017-12-05 20:27:17.195040+0800 TestDemo[4647:1943709] stringCopy2 = 0x6040000367e0
2017-12-05 20:27:17.195138+0800 TestDemo[4647:1943709] mutableCopy = 0x60400025a9d0
2017-12-05 20:27:17.195642+0800 TestDemo[4647:1943709] mutableCopy2 = 0x60400025a610
结果如下:
指向不同地址, 是内容复制,也就是深拷贝 :
- [mutableObject copy]
- [mutableObject mutableCopy]
- [immutableObject mutableCopy]
指向同一个地址,是指针复制,也就是浅拷贝:
- [immutableObject copy]
集合类对象的copy和mutableCopy
不可变集合的copy和mutableCopy
NSArray *array = @[@"1", @"2", @"3", @"4"];
// 不可变集合copy进行了指针拷贝,两者地址一致
NSArray *copyArray = [array copy];
// 不可变集合mutableCopy进行了内容复制,两者地址不一致
NSMutableArray *mutableArray = [array mutableCopy];
NSLog(@"array = %p", array);
NSLog(@"copyArray = %p", copyArray);
NSLog(@"mutableArray = %p", mutableArray);
打印结果如下:
2017-12-05 20:47:31.521896+0800 TestDemo[4719:2064317] array = 0x604000259a10
2017-12-05 20:47:31.522040+0800 TestDemo[4719:2064317] copyArray = 0x604000259a10
2017-12-05 20:47:31.522125+0800 TestDemo[4719:2064317] mutableArray = 0x604000259e30
可变集合的copy和mutableCopy
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array];
// 可变集合的copy进行了内容复制,两者地址不一致
NSArray *copyArray = [mutableArray copy];
// 可变集合的mutableCopy进行了内容复制,两者地址不一致。
NSMutableArray *mutableCopyArray = [mutableArray mutableCopy];
NSLog(@"mutableArray = %p", mutableArray);
NSLog(@"copyArray = %p", copyArray);
NSLog(@"mutableCopyArray = %p", mutableCopyArray);
打印输出如下:
2017-12-05 20:53:23.174059+0800 TestDemo[4762:2113125] mutableArray = 0x600000259fb0
2017-12-05 20:53:23.174210+0800 TestDemo[4762:2113125] copyArray = 0x600000259e90
2017-12-05 20:53:23.174303+0800 TestDemo[4762:2113125] mutableCopyArray = 0x600000259e00
结果如下:
指向不同地址,是单层深拷贝:
- [immutableObject mutableCopy ]
- [mutableObject copy ]
- [mutableObject mutableCopy ]
指向同一个地址,是浅拷贝:
- [immutableObject copy ]
集合的真正深复制:
-
可以用 initWithArray:copyItems: 将第二个参数设置为YES即可深复制
-
将集合进行归档(archive),然后解档(unarchive)。
NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
网友评论