首先我们测试一下这两行代码:
- 测试一:源对象为可变字符串
- (void)test1{
NSMutableString *string=[NSMutableString stringWithFormat:@"1234"];//源对象:不可变字符串
NSString *str1=[string copy];//深拷贝
//只要调用了copy返回对象就是不可变字符串,而源对象是可变字符串,为了不影响源对象字符串,将会内容拷贝一份生成新的对象字符串。
NSLog(@"%p %p",string,str1);//地址不一样,说明产生了新对象
NSLog(@"%@ %@",string,str1);//内容一样,说明拷贝了内容
NSMutableString *str2=[string mutableCopy];//深拷贝
//只要调用了mutableCopy返回对象就是可变字符串,而源对象是也是可变字符串,为了不影响源对象字符串,将会内容拷贝一份生成新的对象字符串。
NSLog(@"%p %p",string,str2);//地址不一样,说明产生了新对象
NSLog(@"%@ %@",string,str2);//内容一样,说明拷贝了内容
}
- 测试二:源对象为不可变字符串
- (void)test2{
NSString *string=@"1234";//源对象:不可变字符串
NSString *str1=[string copy];//浅拷贝
//只要调用了copy返回对象就是不可变字符串,而源对象是不可变字符串,返回对象也是不可变的字符串,因此系统索性会直接拷贝一份内存地址,不会产生新的对象字符串。
NSLog(@"%p %p",string,str1);//打印地址一样,说明了没有新对象产生
NSLog(@"%@ %@",string,str1);//打印一样说明了,说明拷贝了地址
NSMutableString *str2=[string mutableCopy];//深拷贝
//只要调用了mutableCopy返回对象就是可变字符串,而源对象是是不可变字符串,为了不影响源对象字符串,将会内容拷贝一份生成新的对象字符串。
NSLog(@"%p %p",string,str2);//地址不一样,说明产生了新对象
NSLog(@"%@ %@",string,str2);//内容一样,说明拷贝了内容
}
总结:字符串的拷贝,只要拷贝后是可变的还是不可变的只取决于是调用了copy还是mutablecopy,只要调用了copy返回对象就是不可变字符串,只要调用了mutableCopy返回对象就是可变字符串.源对象为不可变字符串时,并调用了copy方法时属于浅拷贝。浅拷贝就是指针的拷贝不会产生新对象,深拷贝是内容的拷贝会产生新对象。结合上面的例子和经验,继续测试一下
- 测试三:源对象为数组
- (void)test3{
NSMutableArray *Marray=[NSMutableArray arrayWithObjects:@"1", nil];
NSArray *array=[Marray copy];//只要调用了copy返回对象就是不可变的
NSLog(@"%p %p",Marray,array);
NSLog(@"%@ %@",Marray,array);
//地址不一样,内容一样:深拷贝;
NSMutableArray *mutablearray=[Marray mutableCopy];//只要调用了mutablecopy返回对象就是可变的
NSLog(@"%p %p",Marray,mutablearray);
NSLog(@"%@ %@",Marray,mutablearray);
//地址不一样,内容一样:深拷贝;
NSArray *array1=@[@"2",@"2"];
NSArray *array11=[array1 copy];//浅拷贝
NSLog(@"%p %p",array1,array11);
NSLog(@"%@ %@",array1,array11);
//地址一样,内容一样:浅拷贝;
NSMutableArray *array2=[array1 mutableCopy];
NSLog(@"%p %p",array1,array2);
NSLog(@"%@ %@",array1,array2);
//地址不一样,内容一样:深拷贝;
}
总结:字符串,数组,字典.....的拷贝过程一样,只要调用了mutablecopy返回对象就是可变的,只要调用了copy返回对象就是不可变的。只要源对象是不可变的,调用了copy,只是指针的拷贝,不会有新对象的产生是浅拷贝, 而调用了mutablecopy,就会产生新对象,是深拷贝。其他的源对象是可变的,都属于深拷贝。
自定义类的拷贝
- (void)viewDidLoad {
[super viewDidLoad];
Person *p=[[Person alloc]init];
p.name=@"张三";
p.age=@"24";
Person *p1=[p copy];
NSLog(@"%@ %@",p1.age,p1.name);
}
#import "Person.h"
@interface Person()<NSCopying>
@end
@implementation Person
- (id)copyWithZone:(NSZone *)zone{
Person *p=[[Person allocWithZone:zone]init];
p.age=self.age;
p.name=self.name;
return p;
}
@end
属性copy,strong
- copy修饰属性
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,copy)NSArray *array;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *MArray=[NSMutableArray array];
self.array=MArray;
NSLog(@"%p %p",MArray,self.array);//打印得到内存地址不同
[MArray addObject:@"1"];
//Marray数组添加元素@“1”后,Marray不发生变化
NSLog(@"%@ %@",MArray,self.array);//打印得到内容不同,说明Marray与self.array互不影响
}
- (void)setArray:(NSArray *)array{
NSArray *arr=[array copy];//深拷贝,arr与array是不同的对象
_array=arr;//_array与array是不同的对象
}
代码说明:以copy修饰的属性,调用的set方法如上:在给成员变量赋值之前,内部先要调用copy方法返回不可变对象,由于源对象Marray是可变的,所有会深拷贝,重新生一个数组对象。即:self.array=Marray是两个不同内存的对象,以后两者改变互不影响。
- copy修饰可变对象所引起的崩溃错误
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,copy)NSMutableArray *array;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.array=[NSMutableArray arrayWithObjects:@"1", nil];
[self.array addObject:@"1"];
}
运行以上代码后会崩溃: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectArrayI addObject:]: unrecognized selector sent to instance 0x6100000043c0'这就是因为错误的修饰所造成的错误。上面代码属性array用copy修饰后返回的真实对象类型是不可变的,即self.array是不可变数组,而不可变数组是不能进行数组的修改,因此系统会以找不到方法2⃣️发生崩溃
- strong修饰属性
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)NSArray *array;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *MArray=[NSMutableArray array];
self.array=MArray;
NSLog(@"%p %p",MArray,self.array);//打印得到内存地址相同
[MArray addObject:@"1"];
//Marray数组添加元素@“1”后,self.array也会添加元素@“1”,因为self.array与Marray所指向的同一地址的对象。
NSLog(@"%@ %@",MArray,self.array);//内容相同,Marray与self.array互相影响。
}
- (void)setArray:(NSArray *)array{
_array=array;//_array与array指针拷贝
}
代码说明:以strong修饰的属性,set方法赋值就是单纯的指针拷贝,不会有新对象产生。即self.array=Marray是两个相同内存的同一个对象,两者改变互相影响。
总结:以stong或copy修饰的属性的区别是:copy在赋值前会先调用copy返回一个不可变对象再赋值给成员变量,set方法传入的源对象如果是可变的,返回的不可变对象就是深拷贝出的一个新对象,这样成员变量和源对象就是两个不同对象,因此两者也不会相互影响。而以strong修饰的属性就是单纯的浅拷贝,最终也是同一对象,两者会互相影响。数组,字典,字符串道理同上。。。。。。。。。。
网友评论