retain 和 copy 的区别。
copy
copy是通过旧对象创建一个新对象,新对象引用计数器为1,与旧对象的引用计数无关。
retain
retain是创建一个指针,对象引用计数加1。retain 出来的指针和原对象的指针指向的内存地址是相同的。
如何实现copy
并不是所有对象都可以进行copy、mutableCopy 。对象如果可以被copy 则需要遵守NSCopying , 如果对象可以被mutableCopying 则需要遵从 NSMutableCopying。如果即可以被copy 也可以被mutableCopy 则需要同时遵守NSCopying 和 NSMutableCopying。
- 遵守 NSCopying 需要实现 copyWithZone : 方法
- 遵守 NSMutableCopying 需要实现 mutableCopyWithZone : 方法
值得注意的是一些API中的类已经遵守了NSCopying 协议或NSMutableCopying 协议,如NSArray等。
复制API中的对象
不可变对象的copy 是浅拷贝,这是拷贝源对象的指针,也就是retain.比如NSArray.
NSArray *array = [NSArray array] ;
// 对于不可变的对象copy只是浅拷贝,retain一下
NSArray *arrayCopy = [array copy] ;
// 通过输出得知两个对象的内存地址相同。
NSLog(@"array retainCount = %lu , array == arrayCopy ? result = %i",[array retainCount],array == arrayCopy) ;
可变对象的copy是创建出新的对象,开辟新的内存空间,真正意义上的复制,如 NSMutableArray.
NSMutableArray *array = [NSMutableArray array] ;
// 对于可变的对象copy是深拷贝,开辟内存空间
NSArray *arrayCopy = [array copy] ;
// 通过输出得知两个对象的内存地址不同,是两块不同的内存空间
NSLog(@"array retainCount = %lu , array == arrayCopy ? result = %i",[array retainCount],array == arrayCopy) ;
mutableCopy
针对不可变对象的mutableCopy,会进行深拷贝,开辟新的内存空间
NSArray *array = [NSArray array] ;
// 对于不可变对象的可变拷贝, 深拷贝,开辟内存空间
NSMutableArray *arrayCopy = [array mutableCopy] ;
// 通过输出得知两个对象的内存地址不同,是两块不同的内存空间
NSLog(@"array retainCount = %lu , array == arrayCopy ? result = %i",[array retainCount],array == arrayCopy) ;
关于数组元素的拷贝
当我们深拷贝数组的时候,数组的元素是浅拷贝。
//将一个可变字符串填充到数组
NSMutableArray * arr = [NSMutableArray arrayWithObjects:[NSMutableString stringWithFormat:@"张三"] , nil];
// 进行数组的copy
NSMutableArray *arrayCopy = [arr copy];
// 获得arr 的第一个元素
NSMutableString *string = [arr objectAtIndex:0];
// 修改第一个元素
[string appendString:@"是个孩子"] ;
// 输出拷贝数组的第一个元素,证明数组元素是浅拷贝.
NSLog([arrayCopy objectAtIndex:0]) ; // 输出张三是个孩子.
如何对数组元素进行彻底的深拷贝?
使用归档技术,这种计数我们在归档的文章中详细讲解.
自定义对象如何copy ?
自定义对象想要被拷贝需要实现NSCopying、NSMutableCopying 。
// Person 类
@interface Person : NSObject <NSCopying,NSMutableCopying>
@property NSObject *obj ;
@end
copy : copyWithZone 方法。
// 响应copy
-(id) copyWithZone:(NSZone *)zone{
// 初始化对象
Person *p = [[[self class] allocWithZone:zone] init];
// 属性拷贝
p.obj = obj ;
// 返回对象
return p ;
}
mutableCopy : mutableCopyWithZone 方法。
// 响应mutableCopy
-(id) mutableCopyWithZone:(NSZone *)zone{
// 初始化对象
Person *p = [[[self class] allocWithZone:zone] init];
// 属性拷贝
p.obj = obj ;
// 返回对象
return p ;
}
关于代码中的[self class] allocWithZone
这是为了便于扩展性,当类被继承的时候,copyWithZone 等相关代码也会继承,这个时候使用 [self class] allocWithZone 可以更具有扩展性。
copy 和 继承
父类的copyWithZone
// 父类的copy 响应方法
-(id) copyWithZone:(NSZone *)zone{
Person *person = [[[self class ] allocWithZone:zone]init];
person.age = age;
person.name = name;
person.address = address ;
return person ;
}
子类的copyWithZone
// 子类的copy 响应方法
-(id) copyWithZone:(NSZone *)zone{
// 先调用父类,让父类copyWithZone copy完父类属性
Child *child = [super copyWithZone:zone] ;
// copy子类属性
child.childName = childName ;
// 返回指针
return child ;
}
时间: 2024-08-24 10:33:59