Foundation框架中使用copy和mutableCopy方法复制对象
Foundation类实现了名为copy和mutableCopy的方法,可以使用这些方法创建对象的副本。通过实现一个符合<NSCopying>协议(用于制作副本)的方法来完成此任务。如果类必须区分要产生对象的是可变副本还是不可变副本,还需要根据<NSMutableCopying>协议实现一个方法。
回顾Foundation类的copy方法,给定前面描述的两NSMutableArray对象dataArray2和dataArray,语句
dataArray2 = [dataArray mutableCopy];
在内存中创建了一个新的dataArray副本,并复制了它的所有元素。随后,执行语句
[dataArray2 removeObjectAtIndex: 0];
删除了dataArray2中的第一个元素,但却不删除dataArray中的。下面的代码就能说明这个问题:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#import <Foundation/NSObject.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <Foundation/NSAutoreleasePool.h>
int
main (
int
argc,
char
*argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *dataArray = [NSMutableArray arrayWithObjects:
@”one”, @”two”, @”three”, @”four”, nil];
NSMutableArray *dataArray2;
// simple assignment
dataArray2 = dataArray;
[dataArray2 removeObjectAtIndex: 0];
NSLog (@”dataArray: “);
for
( NSString *elem in dataArray )
NSLog (@” %@”, elem);
NSLog (@”dataArray2: “);
for
( NSString *elem in dataArray2 )
NSLog (@” %@”, elem);
// try a Copy, then remove the first element from the copy
dataArray2 = [dataArray mutableCopy];
[dataArray2 removeObjectAtIndex: 0];
NSLog (@”dataArray: “);
for
( NSString *elem in dataArray )
NSLog (@” %@”, elem);
NSLog (@”dataArray2: “);
for
( NSString *elem in dataArray2 )
NSLog (@” %@”, elem);
[dataArray2 release];
[pool drain];
return
0;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
dataArray:
two
three
four
dataArray2:
two
three
four
dataArray:
two
three
four
dataArray2:
three
four
|
前面讨论过,赋值语句
dataArray2 = dataArray;
仅仅创建了对内存中同一数组对象的另一个引用。从dataArray2中删除第一个对象并随后输出两个数组对象中的元素,不出意料,这两个引用中的第一个元素(字符串@"one")都会消失。
接下来,创建一个dataArray的可变副本并将它赋值给dataArray2的最终副本。这就在内存中创建了两个截然不同的可变数组,两者都包含三个元素。现在,删除dataArray2中的第一个元素时,不会对dataArray的内容有任何影响,正如程序输出的最后两行验证的一样。
注意,产生一个对象的可变副本并不要求被复制的对象本身是可变的。这种情况同样适用于不可变副本:可以创建可变对象的不可变副本。
还要注意在产生数组的副本时,数组中每个元素的保持计数将通过复制操作自动增1。因此,如果产生数组的副本并随即释放原始数组,那么副本仍然包含有效的元素.
因为dataArray的副本是在程序中使用mutableCopy方法产生的,所以你要负责释放它的内存。这解释了下面这个程序行
[dataArray2 release];
的实质。