关于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;


}

1 0
原创粉丝点击