浅析ObjectiveC 深浅拷贝学习

来源:互联网 发布:淘宝上买号怎么领取 编辑:程序博客网 时间:2024/05/01 02:51

版权声明

此文版权归作者(chen1987lei)所有。欢迎非营利性转载,转载时必须包含原始链接http://www.cocoachina.com/bbs/read.php?tid=80463且必须包含此版权声明的完整内容。


         iPhone开发语言Objective-C是一种简单的计算机语言,简称OC,支持复杂的面向对象编程。Objective C语言,通常写作ObjC和较少用的Objective C或Obj-C,是扩充C的面向对象编程语言。它主要使用于Mac OS X和GNUstep这两个使用OpenStep标准的系统,而在NeXTSTEP和OpenStep中它更是基本语言。ObjectiveC可以在gcc运作的系统写和编译,因为gcc含Objective C的编译器。


在ObjectiveC 中,什么是深浅拷贝? 深浅拷贝分别指深拷贝和浅拷贝,即mutableCopy和copy方法。


copy复制一个不可变对象,而mutableCopy复制一个mutable可变对象。

什么时候用到深浅拷贝?下面举几个例子说明。非容器类对象如NSString,NSNumber等一类对象

示例1:

       // 非容器类对象   

         NSString *str = @"origin string";

         NSString *strCopy = [str copy];        //  不可变

         NSMutableString *mstrCopy = [str mutableCopy];   //  可变

         [mstrCopy appendString:@"??"];

      // 查看内存可以发现,str和strCopy指向的是同一块内存区域,我们称之为弱引用(weak reference)。而mstrCopy是真正的复制,系统为其分配了新的内存空间,保存从str复制过来的字符串值。从最后一行中修改这些值而不影响str和strCopy可以证明。

      运行截图

         

          

        

        

         
示例2:

         NSMutableString *mstr = [NSMutableString stringWithString:@"origin"];

         NSString *strCopy = [mstr copy];

         NSMutableString *mstrCopy = [mstr copy];

         NSMutableString *mstrMCopy = [mstr mutableCopy]; 

         // [mstrCopy appendString:@"1111"];        // error

         [mstr appendString:@"222"];

          [mstrMCopy appendString:@"333"];

          // 以上四个对象所分配的内存都是不一样的。而且对于mstrCopy,它所指向的其实是一个imutable对象,是不可改变的,所以会出错,这点要注意,好好理解。

         

         

            

           

            

容器类对象深浅复制

比如NSArray,NSDictionary等。对于容器类本身,上面讨论的结论也适用,下面讨论的是复制后容器内对象的变化。

示例3:

           // copy返回不可变对象,mutablecopy返回可变对象

              NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];

              NSArray *arrayCopy1 = [array1 copy];

              // arrayCopy1是和array同一个NSArray对象(指向相同的对象),包括array里面的元素也是指向相同的指针  

                                    

                 

             NSLog(@"array1 retain count:%d",[array1 retainCount]);            //  2

             NSLog(@"array1 retain count:%d",[arrayCopy1 retainCount]);    //   2

             NSMutableArray *mArrayCopy1 = [array1 mutableCopy];

             // mArrayCopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的还是同一个对象。mArrayCopy1还可以修改自己的对象。

             [mArrayCopy1 addObject:@"de"]; 

             [mArrayCopy1 removeObjectAtIndex:0];

            // array1和arrayCopy是指针复制,而mArrayCopy1是对象复制,符合前面示例1讨论的结论。mArrayCopy1可以改变其内的元素:删除或添加。但容器内的元素内容都是浅拷贝

示例4:

            NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];

             NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);   // 1

             NSArray *mArrayCopy2 = [mArray1 copy];

             NSLog(@"mArray1 retain count:%d",[mArray1 retainCount]);  // 2

             // mArray1和mArrayCopy2指向同一对象,retain值+1

              NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];

              NSLog(@"mArray1 retain count:%d",[mArray1 retainCount]);    // mArrayCopy2和mArray1指向的是不一样的对象,但是其中的元素都是一样的对象--------同一个指针。

           

               

             NSMutableString *testString = [mArray1 objectAtIndex:0];

              // testString = @"1a1"; // 这样会改变testString的指针,其实是将@"1a1"临时对象赋给了testString

              [testString appendString:@"tail"]; //  这样以上三个数组的首元素都被改变了

           

                   

              // 由此可见,对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝。

示例5:

              NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"first"],[NSString stringWithString:@"b"],@"c",nil];

              NSArray *deepCopyArray = [[NSArray alloc] initWithArray:array copyItems:YES];

              NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];  

                 \

               

                

          // trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的不可变元素其还是指针复制。或者我们自己实现深拷贝的方法。因为如果容器的某一元素是不可变的,那你复制完后该对象仍旧是不能改变的,因此只需要指针复制即可。除非你对容器内的元素重新赋值,否则指针复制已足够。

            // 举个例子,[[array objectAtIndex:0] appendString:@"sd"]后其他的容器内对象并不会受影响。[array objectAtIndex:1,2]和[deepCopyArray objectAtIndex:1,2]尽管是指向同一块内存,但是我们没有办法对其进行修改-----因为它是不可改变的。所以指针复制已经足够。所以这并不是完全意义上的深拷贝。

原创粉丝点击