Objective C中对象的复制 Foundation框架中的文件和目录 Objective C中的文件归档 Objective C中对象的复制 内容概述 概述 对象的浅复制和深复制 NSCopying协议和NSMutableCopying协议 15.1 概述 基本数据类型之间变量的赋值是值传递,而引用类型对象之间对象的赋值是引用传递。这样如果一个对象赋值给另外一个对象,当其中一个对象属性被修改时,另外一个对象的属性也同时被修改。下图描述了对象赋值的过程。 上图所示,定义一个Person对象,有两个属性name和age。假设per1对象的地址是0x123,将per1赋值给per2,是将per1的地址赋值给per2。所以per1和per2地址相同它们指向同一个对象。这样当第一个对象的属性改变时,第二个对象也会跟着改变。为了解决这个问题,使得第一个对象改变时不会影响到第二个对象,我们需要复制对象。 // 测试赋值 -(void)testAssign{ // 实例化Person Person *per1 = [[Person alloc]init]; // 给第一个对象属性赋值 per1.age = 20; per1.name = @"tom"; // 将第一个对象引用赋值给第二个对象 Person *per2 = per1; per1.name = @"big tom"; per1.age = 21; NSLog(@"per1's name=%@,age=%d",per1.name,per1.age); NSLog(@"per2's name=%@,age=%d",per2.name,per2.age); } 上述程序输出结果如下: 2013-04-15 13:49:18.840 chapter15-01[1001:303] per1's name=big tom,age=21 2013-04-15 13:49:18.842 chapter15-01[1001:303] per2's name=big tom,age=21 这个问题同样出现在集合数组中,我们将一个数组赋值给另外一个数组,当删除一个数组中的一个元素时,第二个数组中的元素也将被删除。 // 测试赋值2 -(void)testAssign2{ // 初始化数组 NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil]; // 赋值 NSMutableArray *array2 = array1; // 删除第二个数组中的元素 [array2 removeObjectAtIndex:0]; // 遍历第一个数组 for(NSString *item in array1){ NSLog(@"%@",item); } NSLog(@"%@",@"------------------"); // 遍历第二个数组 for(NSString *item in array2){ NSLog(@"%@",item); } } 程序输出结果如下所示。 2013-04-15 13:52:42.704 chapter15-01[1019:303] 2 2013-04-15 13:52:42.705 chapter15-01[1019:303] 3 2013-04-15 13:52:42.706 chapter15-01[1019:303] ------------------ 2013-04-15 13:52:42.706 chapter15-01[1019:303] 2 2013-04-15 13:52:42.706 chapter15-01[1019:303] 3 15.2 对象的浅复制和深复制 为了避免在15.1中出现的问题,我们可以复制对象。NSObject提供了两个方法,- (id)copy和- (id)mutableCopy,copy方法可以拷贝一个不可变对象,而mutableCopy可以拷贝一个可变对象,例如NSMutableArray、NSMutableSet等。 下面是一个NSMutableArray,我们使用mutableCopy方法拷贝一个对象赋值给一个新对象,这样当从第一个数组中删除一个元素时,第二个数组并没有发生改变。 // 测试拷贝 -(void)testCopy{ // 初始化数组 NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil]; // 拷贝数组 NSMutableArray *array2 = [array1 mutableCopy]; // 删除第二个数组中的元素 [array2 removeObjectAtIndex:0]; // 遍历第一个数组中的元素 for(NSString *item in array1){ NSLog(@"%@",item); } NSLog(@"%@",@"------------------"); // 遍历第二个数组中的元素 for(NSString *item in array2){ NSLog(@"%@",item); } } 上述程序的输出结果如下所示。 2013-04-15 14:01:39.739 chapter15-01[1037:303] 1 2013-04-15 14:01:39.741 chapter15-01[1037:303] 2 2013-04-15 14:01:39.741 chapter15-01[1037:303] 3 2013-04-15 14:01:39.742 chapter15-01[1037:303] ------------------ 2013-04-15 14:01:39.742 chapter15-01[1037:303] 2 2013-04-15 14:01:39.742 chapter15-01[1037:303] 3 对象的复制分为深复制和浅复制,浅复制只复制对象本身,而对象包含或关联的对象并不进行复制。而深复制不光复制对象本身,对象包含或关联的对象将被同时复制。 下面我们定义一个可变数组,可变数组中添加若干可变字符串。如果进行浅复制数组中的元素将会受到影响,如果进行深赋值数组中的元素将不会受到影响。 NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"1"],[NSMutableString stringWithString:@"2"],[NSMutableString stringWithString:@"3"], nil]; // 浅复制 // NSMutableArray *array2 = [array1 mutableCopy]; // 深复制 NSMutableArray *array2 = [NSMutableArray arrayWithCapacity:3]; // 赋值数组中的每一个元素 for(NSString *str2 in array1){ [array2 addObject:[str2 mutableCopy]]; } // 改变第一个数组中的元素 NSMutableString *str = [array1 objectAtIndex:0]; [str appendString:@"changed"]; // 遍历改变后第一个数组中的内容 for(NSString *item in array1){ NSLog(@"%@",item); } NSLog(@"%@",@"------------------"); // 遍历改变后第二个数组中的内容 for(NSString *item in array2){ NSLog(@"%@",item); } 程序运行结果如下所示。 2013-04-15 14:11:10.695 chapter15-01[1051:303] 1changed 2013-04-15 14:11:10.697 chapter15-01[1051:303] 2 2013-04-15 14:11:10.698 chapter15-01[1051:303] 3 2013-04-15 14:11:10.698 chapter15-01[1051:303] ------------------ 2013-04-15 14:11:10.698 chapter15-01[1051:303] 1 2013-04-15 14:11:10.698 chapter15-01[1051:303] 2 2013-04-15 14:11:10.699 chapter15-01[1051:303] 3 15.3 NSCopying协议和NSMutableCopying协议 在前两节中我们使用数组NSArray来模拟对象的拷贝,我们查看源码,发现NSArray类实现了NSCopying协议和NSMutableCopying协议。 @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> - (NSUInteger)count; - (id)objectAtIndex:(NSUInteger)index; @end 如果是我们自己定义的一个类,要想进行对象复制,我们也必须实现NSCopying协议或NSMutableCopying协议,否则,程序将运行失败。 下面我们定义一个Person类,实现NSCopying协议,并实现了(id)copyWithZone:(NSZone *)zone方法。 #import <Foundation/Foundation.h> // 实现NSCopying协议 @interface Person : NSObject <NSCopying> // age 属性 @property int age; // name属性 @property (nonatomic,copy) NSString *name; @end #import "Person.h" @implementation Person @synthesize age; @synthesize name; -(void)setName:(NSString *)name1{ name = [name1 copy]; } // 覆盖拷贝方法 -(id)copyWithZone:(NSZone *)zone{ // NSZone是一个内存区域对象 Person *per = [[Person allocWithZone:zone]init]; return per; } @end Person *per = [[Person alloc]init]; // 如果没有实现Copying协议会出现错误 Person *per2 = [per copy]; 另外,在声明属性时可以使用copy关键字设置属性的set方法的赋值使用copy对象。 @property (nonatomic,copy) NSString *name; -(void)setName:(NSString *)name1{ name = [name1 copy]; } Foundation框架中的文件和目录 Objective C中的文件归档