关于copy 和 mutableCopy的一点思考
来源:互联网 发布:python 元组列表排序 编辑:程序博客网 时间:2024/06/05 03:46
好久没有写博客了,今天得空写一写
前几天,小伙伴微信发过来一段代码,想要对model进行深拷贝,代码如下:
(Person类中没有任何代码)
Person *person1 = [[Personalloc] init];
Person *person2 = [person1mutableCopy];
但是这样会崩溃的,具体原因主要与深拷贝只是相关
如果想要这样的拷贝不崩溃,只能进行拷贝构造了
在Person.h中遵循 <NSMutableCopying>协议,
在Person.m中实现
- (id)mutableCopyWithZone:(NSZone *)zone{
Person *people = [[selfclass] allocWithZone:zone];
return people;
}
这样可以进行深拷贝,那么下面来说说我和小伙伴对深拷贝的一些浅谈吧.
1. copy 和retain
copy 是创建一个新的对象,retain count 为1,开辟一个新的内存,与旧的对象无关. 但属性标识对象内容相同. retain是创建一个指针,引用对象计数+1 . copy 减少对象了对上下文的依赖.
2. copy 和 strong
copy和strong 都是对对象的强引用, 区别和上文retain区别差不多
3. copy 和 mutableCopy
ios 提供copy 和 mutableCopy 两个方法. copy 复制可到的是一个不可变的对象(这一点很重要),因此copy得来的对象,不能进行可变对象方法的操作, mutableCopy复制的对象得到的是一个可变的对象,因此必须要用可变对象来接受复制的对象
下面结合例子来进行理解:
首先先宏定义打印
#define LOG_METHOD_NAME NSLog(@"%@",NSStringFromSelector(_cmd));
#define LOG_OBJ_ADDRESS(obj) NSLog(@"%@ : %p",NSStringFromClass([obj class]),obj);
(一) 常用不可变字符串赋值思考
NSString *str =@"222";
LOG_OBJ_ADDRESS(str)………(1)
NSString *str2 = str;
LOG_OBJ_ADDRESS(str2)………(2)
str2 =@“222”;
LOG_OBJ_ADDRESS(str2)…………(3)
NSString *str3 = [str copy];
LOG_OBJ_ADDRESS(str3)…………(4)
NSString *str3 = @“222”;
LOG_OBJ_ADDRESS(str3)…………(5)
NSString *str4 = [NSStringstringWithFormat:@"%@",@"444"];
LOG_OBJ_ADDRESS(str4)…………(6)
str2 = @“dddd”;
LOG_OBJ_ADDRESS(str2)…………(7)
str3 = @“aaaa”;
LOG_OBJ_ADDRESS(str3)…………(8)
打印的结果是:
_NSCFConstantString : 0x107f85260 (1)
_NSCFConstantString : 0x107f85260 (2)
_NSCFConstantString : 0x107f85260 (3)
_NSCFConstantString : 0x107f85260 (4)
_NSCFConstantString : 0x107f85260 (5)
NSTaggedPointerString : 0xa000000003434343 (6)
_NSCFConstantString : 0x107f852a0 (7)
_NSCFConstantString : 0x107f852b0 (8)
(1)(2)(3)(4)(5) 内存地址相同,说明无论在直接赋值还是copy,都是将两个变量都是指向同一个内存地址. 而且,,在赋的值相同情况下,也是指向同一个内存地址, 但是在赋值不一样的情况下,如 (7) (8) 会开辟出一个新的内存地址,相当于深拷贝
问题一:那么问题来了,既然这样赋值就能实现字符串的深拷贝,减少了两个字符串之间影响,那么copy有什么用呢???
(二) 关于copy 在定义属性时的作用
(1) 不可变字符串
Person.h
@property (nonatomic,strong) NSString *stt_strong;
@property (nonatomic,copy) NSString * stt_copy;
Person.m
NSString *stt =@"字符串";
LOG_OBJ_ADDRESS(stt)
self.stt_strong = stt;
LOG_OBJ_ADDRESS(self.stt_strong)
self.stt_copy = stt;
LOG_OBJ_ADDRESS(self.stt_copy)
stt =@"字符串改变了";
LOG_OBJ_ADDRESS(self.stt_strong)
LOG_OBJ_ADDRESS(stt)
LOG_OBJ_ADDRESS(self.stt_copy)
打印结果:
__NSCFConstantString : 0x10f36e2c0字符串
__NSCFConstantString : 0x10f36e2c0字符串
__NSCFConstantString : 0x10f36e2c0字符串
__NSCFConstantString : 0x10f36e2c0字符串
__NSCFConstantString : 0x10f36e2e0字符串改变了
__NSCFConstantString : 0x10f36e2c0字符串
结论:在定义不可变字符串时,属性定义用copy 和 strong 中任意一种修饰,其效果是一样的,
原有字符串值改变,对全局属性没有任何影响,这相当于在同一个内存块儿内,有不同的区域进行存储字符串.
当全局变量发生改变的时候,会重新开辟内存空间,相当于深拷贝,进行存储
(2)可变字符串
Person.h
@property (nonatomic,strong) NSMutableString *mutStr_strong;
@property (nonatomic,copy) NSMutableString *mutStr_copy;
Person.m
NSMutableString *mutS = [NSMutableStringstringWithFormat:@"rrrrrr"];
LOG_OBJ_ADDRESS(mutS) ………………………(1)
self.mutStr_strong = mutS;
LOG_OBJ_ADDRESS(self.mutStr_strong); ………………………(2)
self.mutStr_copy = mutS;
LOG_OBJ_ADDRESS(self.mutStr_copy) ………………………(3)
[mutSappendFormat:@"tttttttt"];
LOG_OBJ_ADDRESS(mutS); ………………………(4)
LOG_OBJ_ADDRESS(self.mutStr_strong) ………………………(5)
LOG_OBJ_ADDRESS(self.mutStr_copy) ………………………(6)
打印结果:
__NSCFString : 0x600000073640 rrrrrr ………………………(1)
__NSCFString : 0x600000073640 rrrrrr ………………………(2)
NSTaggedPointerString : 0xa007272727272726 rrrrrr ………………………(3)
__NSCFString : 0x600000073640 rrrrrrtttttttt ………………………(4)
__NSCFString : 0x600000073640 rrrrrrtttttttt ………………………(5)
NSTaggedPointerString : 0xa007272727272726 rrrrrr ………………………(6)
在可变字符串,属性定义是,strong修饰的mutStr_strong,在(2)中赋值时,内存地址没有变化,同时类型还是可变字符串(__NSCFString), 但是(3)中用copy修饰的mutStr_copy,地址变化,并且类型不成不可变的字符串常亮
再看打印结果中(5)在局部变量mutS变化后,mutStr_strong跟着变化了, mutStr_copy没有变化
这就说明,为什么自定义属性修饰时,具有可变属性的obj(NSString(NSMutableString) ,NSArray(NSMutableArray), NSDictionary(NSMutableDictionay)), 在不可变属性定义时,用copy的原因了,比如:
@property (nonatomic,copy) NSString * str;
就是为了防止在修改局部变量时,影响全局变量
问题二: 那么还有一个问题, 上面mutStr_copy,在进行[self.mutStr_copyappendFormat:@“aaaa”];
会出现崩溃,崩溃原因是没有找到appendFormat的方法,原因是,在copy修改时的属性,其进行copy操作后,将变成不可变的
所以,在上述对可变字符串mutStr_copy修饰中,用strong, 但在赋值时,用深拷贝
操作如下:
Person.h
@property (nonatomic,strong) NSMutableString *mutStr_copy;
Person.m
self.mutStr_copy = [mutSmutableCopy];
LOG_OBJ_ADDRESS(self.mutStr_copy)
这样self.mutStr_copy的类型还是NSMutableString,并且不会收局部变量的影响
上面的2这个整个结论是,在不可变对象(其具有可变的子类时)定义时,用copy修饰,在可变变量定义时,用strong修饰,但是用记得用mutableCopy,深拷贝
3. 对类进行拷贝构造
如果想要实现对类实现copy和mutablecopy,那么就要遵循NSCopying , NSMutableCopying
举个例子:
外部要实现这样的效果:
//深拷贝
Person *person1 = [[Personalloc] init];
person1.name =@"ddd";
person1.age =18;
person1.mutArr = [NSMutableArrayarrayWithObjects:@"122",nil];
Person *person2 = [person1mutableCopy];
或者:
Person *person2 = [person1copy];
Person中类的实现
Person.h
@interface Person :NSObject<NSCopying,NSMutableCopying>
@property (nonatomic,copy) NSString *name;
@property (nonatomic,strong)NSMutableArray *mutArr;
@property (nonatomic,assign) int age;
@end
Person.m
拷贝构造
- (id)copyWithZone:(nullableNSZone *)zone{
Person *people = [[selfclass] allocWithZone:zone];
people.name = [_namecopy];
people.age =_age;
people.mutArr = [_mutArrmutableCopy];
return people;
}
- (id)mutableCopyWithZone:(nullableNSZone *)zone{
Person *people = [[selfclass] allocWithZone:zone];
people.name = [_namecopy];
people.age =_age;
people.mutArr = [_mutArrmutableCopy];
return people;
}
- 关于copy 和 mutableCopy的一点思考
- 关于NSString的copy和mutableCopy
- mutableCopy和copy的区别
- copy和mutableCopy的区别
- mutableCopy和copy的区别
- 关于oc的学习笔记 -copy和mutableCopy
- copy和mutableCopy的深、浅拷贝
- 深入对象的copy和mutableCopy
- copy mutablecopy 和 retain 的 区别
- Objective-c的copy和mutableCopy
- OC-057.copy和MutableCopy的使用
- copy和mutableCopy
- iphone copy 和mutablecopy
- copy和mutablecopy浅见
- copy和mutablecopy
- copy和mutablecopy
- copy和mutablecopy
- copy和mutableCopy
- IAR6.3的安装
- Android性能优化系列之Bitmap图片优化
- Spring学习——Spring中定时器实现
- ContentProvider的使用方法
- 怎样清除CMOS密码
- 关于copy 和 mutableCopy的一点思考
- 使用Qt导出文本文件
- as升级2.3后新建Activity自动引入约束布局
- 监控mysql qps
- bootstrap-tree增删改(修复更新BUG)
- Ubuntu终端常用的快捷键
- [JavaScript]addLoadEvent方法--摘自<JavaScript+DOM编程艺术>
- 阿里云服务器的 mysql root密码忘记了咋办
- wxpython学习总结(一)