iOS-copy与mutableCopy浅析
在iOS开发中,当提到深拷贝和浅拷贝的时候,大家都说懂,简单;都会说,浅拷贝:指针(地址)拷贝,不会产生新对象;深拷贝:内容拷贝,会产生新对象,但当问及大家copy与mutableCopy的时候,他们各自是深拷贝还是浅拷贝的时候,谁又有底气答对呢?下面一起研究下吧
1、不可变字符串的拷贝
NSString *string = @"string"; NSString *str1 = [string copy]; // 没有产生新对象 【浅拷贝】 NSMutableString *str2 = [string mutableCopy]; // 产生新对象 【深拷贝】 NSLog(@"%p %p %p", string, [string copy], [string mutableCopy]);
打印结果如下:
根据打印结果解析:
当不可变字符串调用copy的时候,指针地址没有发生改变,也就意味着没有产生新的对象,所以属于浅拷贝;
当不可变字符串调用mutableCopy的时候,指针地址发生了改变,意味着产生新的对象,所以属于深拷贝。
2、可变字符串的拷贝
NSMutableString *string = [NSMutableString string]; [string appendString:@"text1"]; NSString *str1 = [string copy]; // 产生新对象,变为不可变字符串【深拷贝】 NSMutableString *str2 = [string mutableCopy];// 产生新对象,还是可变字符串 【深拷贝】 [str2 appendString:@"text2"]; NSLog(@"%p %p %p", string, [string copy], [string mutableCopy]); NSLog(@"%@ %@ %@", string, str1, str2);
打印结果如下:
根据打印结果解析:
当可变字符串调用copy的时候,指针地址发生了改变,也就意味着产生新的对象,所以属于深拷贝;
当可变字符串调用mutableCopy的时候,指针地址发生了改变,意味着产生新的对象,所以属于深拷贝。
3、不可变数组的拷贝
NSArray *array = @[@"text1", @"text2"]; NSArray *array1 = [array copy]; // 没有产生新对象 【浅拷贝】 NSMutableArray *array2 = [array mutableCopy]; // 产生新对象,变为可变数组【深拷贝】 [array2 addObject:@"text3"]; NSLog(@"%p %p %p", array, array1, array2); NSLog(@"%@ %@ %@", array, array1, array2);
打印结果如下:
根据打印结果解析:
当不可变数组调用copy的时候,指针地址没有发生改变,意味着没有产生新的对象,所以属于浅拷贝;
当不可变数组调用mutableCopy的时候,指针地址发生了改变,意味着产生新的对象,所以属于深拷贝。
4、可变数组的拷贝
NSMutableArray *mutableArray = @[@"text1", @"text2"].mutableCopy; NSArray *array1 = [mutableArray copy]; // 产生新对象,变为不可变数组【深拷贝】 NSMutableArray *mutableArray1 = [mutableArray mutableCopy]; // 产生新对象,变为可变数组 【深拷贝】 [mutableArray1 addObject:@"text3"]; NSLog(@"%p %p %p", mutableArray, [mutableArray copy], [mutableArray mutableCopy]); NSLog(@"%@ %@ %@", mutableArray, array1, mutableArray1);
打印结果如下:
根据打印结果解析:
当可变数组调用copy的时候,指针地址发生了改变,也就意味着产生新的对象,所以属于深拷贝;
当可变数组调用mutableCopy的时候,指针地址发生了改变,意味着产生新的对象,所以属于深拷贝。
5、自定义对象的拷贝
由于自定义对象不考虑可变,所以忽略mutableCopy
首先,当对象需要调用 copy 的时候,需要遵守遵守 NSCopying 协议 和 调用 copyWithZone:这个方法
@interface Dog : NSObject /** 姓名 */ @property (nonatomic, copy) NSString *name; /** 年龄 */ @property (nonatomic, assign) int age; @end // 需要遵守 NSCopying 协议 @interface Dog () @end @implementation Dog // 当对象需要调用 copy 的时候,需要调用 copyWithZone:这个方法 - (id)copyWithZone:(NSZone *)zone { Dog *dog = [[Dog allocWithZone:zone] init]; dog.name = self.name; dog.age = self.age; return dog; } @end
Dog *dog = [[Dog alloc] init]; // [object copyWithZone:zone] dog.name = @"huahua"; dog.age = 1; Dog *newDog = [dog copy]; // 产生新对象【深拷贝】 NSLog(@"%@ %@",dog,newDog); NSLog(@"%@ %@",dog.name,newDog.name);
打印结果如下:
根据打印结果解析:
当自定义对象调用copy的时候,指针地址发生了改变,也就意味着产生新的对象,所以属于深拷贝;
6、属性中的copy 和 strong
在平时定义属性的时候,对于NSString 和 block 我们经常用 copy 来修饰
数组和字典等类型用 strong 来修饰;
当使用 copy 修饰属性的时候,属性的setter方法会调用[object copy]产生新的对象,
这样,当原object对象的值发生改变时,并不影响新对象值;
// 定义NSString @property(nonatomic, copy) NSString *name; . . . // 当调用上面的copy的时候,等价于下面的代码 - (void)setName:(NSString *)name { if (_name != name) { [_name release]; _name = [name copy]; } }
当使用 strong 修饰属性的时候,属性的setter方法会直接强引用该对象,
这样,当原object对象的值发生改变时,新对象的属性也改变;
例如:我们平时使用strong修饰的NSMutableArray,这个可变数组在当前文件中只有一个,而且是可变的;
/** 数组 */ @property(nonatomic,strong)NSMutableArray *array; . . . // 当调用上面的strong的时候,等价于下面的代码 -(void)setArray:(NSMutableArray *)array{ _array = array; }
以前面的自定义Dog对象进行举例:
// 定义一个可变的字符,作为小狗的name NSMutableString *dogName = [NSMutableString stringWithString:@"huahua"]; // dogName == "huahua" Dog *dog = [[Dog alloc] init]; // 将字符赋值给dog的name属性 dog.name = dogName; // 当小狗的name值发生改变时 [dogName appendString:@"lvlv"]; // dogName == "huahualvlv" // 小狗的名还是原来的姓名 NSLog(@"%@",dog.name); // 打印结果:huahua
分析:当给dog.name 赋值时,会将 [dogName copy] 后的结果赋值给 dog.name,这样,当dogName字符的值发生改变后,不会影响 dog.name 的值;
总结:当不可变类型对象调用copy拷贝后,不会产生新的对象,属于浅拷贝,其他类型对象不管调用copy亦或是mutableCopy,都会产生新的对象,属于深拷贝!