IOS ObjectiveC中的赋值与对象拷贝
IOSObjectiveC中的赋值与对象拷贝
在开发过程中我们经常会遇到对象拷贝的问题,下面我们分别讨论赋值操作、对象拷贝、以及浅拷贝(Shallowcopy)与深拷贝(Deepcopy)的区别与各自的实现方式。
一、不同对象的赋值操作
Objective-C中有两类对象,一类是结构体(或者基本数据类型也算),另一类是NSObject对象。
对于结构体,代码直接会操作其实体,因此赋值操作会创建一个源对象的副本(一个新的对象);而对于NSObject对象,必须使用指针来操作对象,所以其赋值操作相当于复制了指针,而非对象,也就是说赋值操作使得源指针和新指针都指向同一个NSObject对象。这样讲有些难以理解,请看下面的代码:
//main.m #import@interfaceTestObject:NSObject { @public intx; inty; } @end @implementationTestObject @end typedefstructTestStruct { intx; inty; } TestStruct; intmain(intargc,constchar*argv[]) { @autoreleasepool{ TestStructts1={100,50}; NSLog(@"ts1:%p,%d,%d",&ts1,ts1.x,ts1.y); TestStructts2=ts1; NSLog(@"ts2:%p,%d,%d",&ts2,ts2.x,ts2.y); TestObject*to1=[[[TestObjectalloc]init]autorelease]; NSLog(@"to1:%p,%d,%d",to1,to1->x,to1->y); TestObject*to2=to1; NSLog(@"to2:%p,%d,%d",to2,to2->x,to2->y); } return0; }
程序的运行结果如下:
ts1:0x7fff63463898,100,50 ts2:0x7fff63463890,100,50 to1:0x7fc342d00370,0,0 to2:0x7fc342d00370,0,0
程序代码首先定义了一个类TestObject(继承自NSObject),然后又定义了一个结构体TestStruct。这两者都包含两个整型的成员变量x和y。然后在main函数中,程序首先为TestStruct结构体ts1分配内存空间,并为其成员变量赋初值,x为100,y为50。然后通过NSLog函数打印出该结构体的地址和成员变量的值,即输出的第一行内容。接着,程序执行了赋值语句,将ts1赋值给另一个TestStruct结构体对象ts2,这条语句会为ts2分配另一块内存,然后把ts1的每个成员变量的值复制过来。第二行输出也可以看出来,地址不一样了,所以如果修改ts1的成员变量的值,是不会影响ts2的。
接着再来看TestObject。程序接着使用alloc静态方法分配了一块新的内存空间,然后通过init实例方法进行初始化(所有成员变量的值为0),最后将该内存空间的首地址返回。to1的实质就是一个指针,指向创建的TestObject对象。接着,程序将to1赋值给to2。to2也是一个指向TestObject对象的指针,其值与to1一样,即两者都指向同一个对象。所以在这种情况下,对to1的修改会同时影响to2。
二、对象拷贝
Foundation框架的NSObject类提供了两个方法,分别是copy和mutableCopy方法,用于对NSObject对象进行拷贝操作。copy方法会调用NSCopying协议的copyWithZone:方法,而mutableCopy会调用NSMutableCopying协议的mutableCopyWithZone:方法。将上面的代码修改如下:
#import@interfaceTestObject:NSObject { @public intx; inty; } @end @implementationTestObject -(NSString*)description { return[NSStringstringWithFormat:@"%@:%p,x:%d,y:%d",[selfclass],self,x,y]; } @end typedefstructTestStruct { intx; inty; } TestStruct; intmain(intargc,constchar*argv[]) { @autoreleasepool { TestObject*to1=[[[TestObjectalloc]init]autorelease]; to1->x=100;to1->y=50; TestObject*to2=[[[TestObjectalloc]init]autorelease]; to2->x=200;to2->y=400; TestObject*to3=[[[TestObjectalloc]init]autorelease]; to3->x=300;to3->y=500; //创建包含to1,to2,to3的数组array1 NSArray*array1=[NSArrayarrayWithObjects:to1,to2,to3,nil]; NSLog(@"array1:%p,\n%@",array1,array1); //array2是array1调用copy的结果 NSArray*array2=[array1copy]; NSLog(@"array2:%p,\n%@",array2,array2); [array2release]; //mutableArray2是array1调用mutableCopy的结果 NSMutableArray*mutableArray2=[array1mutableCopy]; NSLog(@"mutableArray2:%@,%p,\n%@",[mutableArray2class],mutableArray2,mutableArray2); [mutableArray2removeLastObject]; NSLog(@"AfterremovelastobjectofmutableArray2"); NSLog(@"array1:%p,\n%@",array1,array1); NSLog(@"array2:%p,\n%@",array2,array2); NSLog(@"mutableArray2:%p,\n%@",mutableArray2,mutableArray2); //mutableArray3是mutableArray2调用mutableCopy的结果 NSMutableArray*mutableArray3=[mutableArray2mutableCopy]; NSLog(@"mutableArray3:%p,\n%@",mutableArray3,mutableArray3); [mutableArray2release]; //array4是mutableArray3调用copy的结果 NSArray*array4=[mutableArray3copy]; NSLog(@"array4:%@,%p,\n%@",[array4class],array4,array4); [mutableArray3release]; [array4release]; } return0; }
程序的运行结果如下:
2012-03-2219:20:49.548ObjectCopy[18042:403]array1:0x7f9071414820, ( "TestObject:0x7f90714141b0,x:100,y:50", "TestObject:0x7f90714141c0,x:200,y:400", "TestObject:0x7f9071414230,x:300,y:500" ) 2012-03-2219:20:49.550ObjectCopy[18042:403]array2:0x7f9071414820, ( "TestObject:0x7f90714141b0,x:100,y:50", "TestObject:0x7f90714141c0,x:200,y:400", "TestObject:0x7f9071414230,x:300,y:500" ) 2012-03-2219:20:49.551ObjectCopy[18042:403]mutableArray2:__NSArrayM,0x7f9072800000, ( "TestObject:0x7f90714141b0,x:100,y:50", "TestObject:0x7f90714141c0,x:200,y:400", "TestObject:0x7f9071414230,x:300,y:500" ) 2012-03-2219:20:49.552ObjectCopy[18042:403]AfterremovelastobjectofmutableArray2 2012-03-2219:20:49.552ObjectCopy[18042:403]array1:0x7f9071414820, ( "TestObject:0x7f90714141b0,x:100,y:50", "TestObject:0x7f90714141c0,x:200,y:400", "TestObject:0x7f9071414230,x:300,y:500" ) 2012-03-2219:20:49.553ObjectCopy[18042:403]array2:0x7f9071414820, ( "TestObject:0x7f90714141b0,x:100,y:50", "TestObject:0x7f90714141c0,x:200,y:400", "TestObject:0x7f9071414230,x:300,y:500" ) 2012-03-2219:20:49.553ObjectCopy[18042:403]mutableArray2:0x7f9072800000, ( "TestObject:0x7f90714141b0,x:100,y:50", "TestObject:0x7f90714141c0,x:200,y:400" ) 2012-03-2219:20:49.557ObjectCopy[18042:403]mutableArray3:0x7f90729000d0, ( "TestObject:0x7f90714141b0,x:100,y:50", "TestObject:0x7f90714141c0,x:200,y:400" ) 2012-03-2219:20:49.558ObjectCopy[18042:403]array4:__NSArrayI,0x7f9071416e70, ( "TestObject:0x7f90714141b0,x:100,y:50", "TestObject:0x7f90714141c0,x:200,y:400" )
程序的运行结果有几点值得注意,首先是array1与array2的地址相同,因为NSArray对象在创建之后是不可以修改的。其次,NSArray的mutableCopy方法会返回一个NSMutableArray对象。第三,对于NSArray或者NSMutableArray来说,mutableCopy方法会创建新的可变数组对象,但其每个数组成员的值仅仅是原数组的一个指针赋值,这就是浅拷贝。而与之相对的则是深拷贝,即复制数组时不是复制数组每个元素的引用,而是创建一个与之相同的新对象。
第四,在NSArray对象上调用mutableCopy方法返回一个NSMutableArray对象,而在NSMutableArray对象上调用copy方法则返回一个NSArray对象,而不是NSMutableArray对象。
当然,以上讨论的是Foundation框架中的NSArray与NSMutableArray类,如果想要实现对自己创建的类的对象进行拷贝,则需要让类实现NSCopying协议。
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!