iOS 自习室 - 什么是?NSCopying,NSMutableCopying

33 阅读3分钟

什么是?NSCopying,NSMutableCopying

NSCopying 协议

自定义类支持拷贝操作,需实现 NSCopyingNSMutableCopying 协议。

如果向未实现相应方法的系统类或者自定义类发送 copy 或者 mutableCopy 消息,则会 crash。

-[Person copyWithZone:]: unrecognized selector sent to instance 0x600001f17820
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person copyWithZone:]: unrecognized selector sent to instance 0x600001f17820'**
/** **************** * *Basic protocols ** **************** ** **/
@protocol NSCopying
- (id)copyWithZone:(nullable NSZone *)zone;
@end

@protocol NSMutableCopying
- (id)mutableCopyWithZone:(nullable NSZone *)zone;
@end

// 事例
- (id)copyWithZone:(NSZone *)zone {
    return [[[self class] allocWithZone:zone] init];
}

注意:模型数组内元素中模型必须要实现copying协议,模型内如果有嵌套模型,也需要实现copying协议,否则执行对对象拷贝操作会出现崩溃;

浅复制和深复制

系统非集合类(NSString,NSMutableString)

NSString *name = @"张三";
NSString *name1 = [name copy];
NSMutableString *name2 = [name mutableCopy];
NSLog(@"name = %p",name);
NSLog(@"name1 = %p",name1);
NSLog(@"name2 = %p",name2);
输出-----------------------------------------
name = 0x100cc5168
name1 = 0x100cc5168
name2 = 0x60000134ffc0
NSMutableString *name = [NSMutableString stringWithString:@"张三"];
NSMutableString *name1 = [name copy];    
NSMutableString *name2 = [name mutableCopy];
NSLog(@"name = %p",name);
NSLog(@"name1 = %p",name1);
NSLog(@"name2 = %p",name2);
-------------------------------------------------------------------
name = 0x60000338e4f0
name1 = 0x600003d91bc0
name2 = 0x60000338d8c0
  • 向不可变对象发送 copy,进行的是指针拷贝;
  • 向不可变对象发送 mutalbeCopy 消息,进行的是内容拷贝;
  • 向可变对象发送 copy 或 mutableCopy,进行的是内容拷贝;

系统集合类(NSArray,NSMutableArray)

NSArray *array = @[@"张三",@"李四"];
NSArray *array1 = [array copy];
NSMutableArray *array2 = [array mutableCopy];
------------------------------------------------------------------------------
array = 0x6000012828c0      array1 = 0x6000012828c0       array2 = 0x600001cc0de0
array[0] = 0x104a84168      array1[0] = 0x104a84168       array2[0] = 0x104a84168
  • 不可变对象 copy,是浅拷贝,也就是说指针复制;
  • 不可变对象 mutableCopy,是单层深复制。
NSMutableArray *array = [NSMutableArray arrayWithArray:@[@"张三",@"李四"]];
NSMutableArray *array1 = [array copy];
NSMutableArray *array2 = [array mutableCopy];
-------------------------------------------------------------------------------
array = 0x6000016ba370      array1 = 0x6000018c2480       array2 = 0x6000016ba070
array[0] = 0x10491b168      array1[0] = 0x10491b168       array2[0] = 0x10491b168
  • 可变对象 copy 和 mutableCopy 均是单层深拷贝,也就是说单层的内容拷贝;

注意:可变对象 copy 后,变成了非可变对象,不能使用可变对象的方法。

如何实现数组的完全复制

1、创建新数组,便利 copy 元素

NSMutableArray *array = [NSMutableArray array];
for (Person *person in dataSourceAry) {
    [array addObject:[person copy]];
}

2、数组系统方法,需要 copy 的元素需要实现 NSCopying、NSMutableCopying 协议

- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;

3、归档

  NSArray *dataArray1 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:dataArray]];

属性 copy strong

@property (nonatomic, copy)   NSString *nickName;
@property (nonatomic, strong) NSString *name;

NSMutableString *aaaName = [[NSMutableString alloc] initWithString:@"张三"];
self.nickName = aaaName;
self.name = aaaName;
[aaaName appendString:@",你好"];
NSLog(@"aaaName = %p",aaaName);
NSLog(@"nickName = %p name = %p",self.nickName,self.name);
NSLog(@"nickName = %@ name = %@",self.nickName,self.name);
---------------------------------------------------------------------------
aaaName = 0x600000760bd0
nickName = 0x600000960e60 name = 0x600000760bd0
nickName = 张三 name = 张三,你好
copy setter
- (void)setName:(NSString *)name {
    if (_name != name) {
        [_name release];
        _name = [name copy];
    }
}

strong setter
- (void)setName:(NSString *)name {
    if (_name != name) {
        [_name release];
        _name = [name retain];
    }
}

copy:拷贝一份不可变副本赋值给属性;所以当原对象值变化时,属性值不会变化;
strong:有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性;