Chapter 11 : 复制对象

 

1. 回顾继承部分的代码如下:

 1 // XYPoint类声明
 2 // XYPoint.h文件
 3 
 4 #import <Foundation/Foundation.h>
 5 
 6 @interface XYPoint : NSObject
 7 {
 8     int x;
 9     int y;
10 }
11 
12 @property int x;
13 @property int y;
14 
15 - (void)setX:(int)xVal andY:(int)yVal;
16 
17 @end
 1 // XYPoint类定义
 2 // XYPoint.m文件
 3 
 4 #import "XYPoint.h"
 5 
 6 @implementation XYPoint
 7 
 8 @synthesize x;
 9 @synthesize y;
10 
11 - (void)setX:(int)xVal andY:(int)yVal
12 {
13     x = xVal;
14     y = yVal;
15 }
16 
17 @end
 1 // Rectangle类声明
 2 // Rectangle.h文件
 3 
 4 #import <Foundation/Foundation.h>
 5 
 6 @class XYPoint;
 7 
 8 @interface Rectangle : NSObject
 9 {
10     int        width;
11     int        height;
12     XYPoint *origin;
13 }
14 
15 @property int width;
16 @property int height;
17 
18 - (XYPoint *)origin;
19 - (void)setOrigin:(XYPoint *)pt;
20 - (void)setWidth:(int)w andHeight:(int)h;
21 - (int)area;
22 - (int)perimeter;
23 
24 @end    
 1 // Rectangle类定义
 2 // Rectangle.m
 3 
 4 #import "Rectangle.h"
 5 
 6 @implementation Rectangle
 7 
 8 @synthesize width;
 9 @synthesize height;
10 
11 - (void)setWidth:(int)w andHeight:(int)h
12 {
13     width = w;
14     height = h;
15 }
16 
17 - (void)setOrigin:(XYPoint *)pt
18 {
19     origin = pt;
20 }
21 
22 - (XYPoint *)origin
23 {
24     return origin;
25 }
26 
27 - (int)area
28 {
29     return width * height;
30 }
31 
32 - (int)perimemter
33 {
34     return (width + height) * 2;
35 }
36 
37 @end
 1 // main()
 2 
 3 #import "Rectangle.h"
 4 #import "XYPoint.h"
 5 
 6 int main(int argc, const char *argv[])
 7 {
 8     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 9 
10     Rectangle *myRect = [[Rectangle alloc] init];
11     [myRect setWidth:5 andHeight:8];
12     
13     XYPoint *myPoint = [[XYPoint alloc] init];
14     [myPoint setX:100 andY:200];
15 
16     myRect.origin = myPoint;
17 
18     NSLog(@"Origin at (%i, %i)", myRect.origin.x, myRect.origin.y);
19     
20     // Key Line, Attention!!!
21     [myPoint setX:50 andY:50];
22 
23     NSLog(@"Origin at (%i, %i)", myRect.origin.x, myRect.origin.y);
24 
25     [myRect release];
26     [myPoint release];    
27 
28     [pool drain];
29 
30     return 0;
31 }

 

 注意main()方法的Line 16

    myRect.origin = myPoint;

这样赋值的结果仅仅是将对象myPoint的地址复制到myRect.origin中,即在赋值操作结束时,myRect.origin和myPoint都指向内存中的同一个地址。

所以,将一个变量赋值给另一个对象仅仅是创建另一个对这个对象的引用。即有:

1 NSMutableArray *dataArray1;
2 // 完成dataArray1对象的数据初始化
3 ...
4 NSMutableArray *dataArray2;
5 dataArray2 = dataArray1;
6 
7 [dataArray2 removeObjectAtIndex:0];

 

这样在Line 7中的removeObjectAtIndex将从这两个变量引用的同一个数组中删除第一个元素。

 

2. 复制对象示例代码:

 1 #import <Foundation/Foundation.h>
 2 
 3 int main(int argc, const char *argv[])
 4 {
 5     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 6 
 7     NSMutableArray *dataArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", @"four", nil]];
 8     NSMutableArray *dataArray2;
 9     
10     // Key Line, 因为没有复制对象,所以dataArray和dataArray2指向的数据是同一个内存地址
11     dataArray2 = dataArray;
12     [dataArray2 removeObjectAtIndex:0];
13     NSLog(@"dataArray:");
14     for (NSString *elem in dataArray)
15         NSLog(@"%@", elem);
16 
17     NSLog(@"dataArray2:")
18     for (NSString *elem in dataArray2)
19         NSLog(@"%@", elem);
20 
21     // 执行复制对象
22     dataArray2 = [dataArray mutableCopy];
23     [dataArray2 removeObjectAtIndex:0];
24     NSLog(@"dataArray");
25     for (NSString *elem in dataArray)
26         NSLog(@"%@", elem);
27     
28     NSLog(@"dataArray2:");
29     for (NSString *elem in dataArray2)
30         NSLog(@"%@", elem);
31 
32     [pool drain];
33 
34     return 0;
35 }

 

3. copy和mutableCopy : 利用copy和mutableCopy的方法,可以创建对象的副本, 即:

1 dataArray2 = [dataArray mutableCopy];

 

意义是在内存中创建一个新的dataArray副本,并复制了它的所有元素。随后执行语句:

1 [dataArray2 removeObjectAtIndex:0];

 

删除了dataArray2中的第一个元素,但不会删除dataArray中的。

PS :

-> 产生一个对象的可变副本并不要求被复制的对象本身是可变的,也可以创建可变对象的不可变副本。

-> 在产生数组的副本时,数组中每个元素的Retain Count将通过复制操作自动增1。所以,需要执行

1 [dataArray2 release];

 释放它的内存。

 

4. 浅复制和深复制:

示例代码:

 

此处由于使用的浅复制,所以在执行

    [mStr appendString:@"ONE"];

后,dataArray与dataArray2的第一个元素都发生了改变。这里可理解为dataArray里存储的元素本来就是一个内存地址(NSMutableString对象),

在复制地过程中虽然生成了dataArray的副本给dataArray2,但是他们存储的元素指向的内存地址依然相同,故字符串的改变都是指向同一个内存地址。

-> 深复制:要解决上面的问题,那就得在创建数组副本时也要创建数组中每个元素对象的副本:

     mStr = [NSMutableString stringWithString:[dataArray2 objectAtIndex:0]];

然后,可以更改mStr, 并使用replaceObjectAtIndex:withObject:方法将它添加到数组中:

    [mStr appendString:@"ONE"];

    [dataArray2 replaceObjectAtIndex:0 withObject:mStr];

这样,改变的数据就不会影响到[dataArray objectAtIndex:0], 因为这个数组元素已经经过的深复制。

 

 

 

 

 

posted on 2012-09-28 16:45  BankFish  阅读(555)  评论(0编辑  收藏  举报