1
.任何你创建的对象你都能获得其所有权。
这里的创建包括使用alloc,
new
,copy等关键字来获得一个对象。
2
.你可以通过retain来获得一个对象的所有权。
除了创建对象外,获得某个对象所有权的唯一方法就只有给该对象发retain消息。
一旦通过retain获得了该对象的所有权,就必须遵守上面红字标注的原则:如果你拥有一个对象,那么你就有责任去释放它。
3
.如果你不再需要一个对象了,你就必须释放其所有权。
4
.你不能释放非你所有的对象所有权。
-》所有由alloc、copy(mutablecopy)、retain、new创建的object,必须手动release(或autorelease) 。
autorelease不是自动释放,是AutoreleasePool的实例,在runloop中被”稍后“释放。
- 创建对象 alloc 、new,初始的retainCount都是1,copy使retainCount加1,
- mutableCopy的retainCount保持原来的值不变,但是当前的对象的retainCount为1。
- 如:NSMutableArray *mArrayCopy1 = [array1 mutableCopy];
- array1的retainCount保持原来的值不变;mArrayCopy1的retainCount为1;
-
NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil]; NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]); NSArray *mArrayCopy2 = [mArray1 copy]; NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]); NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy]; NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]); [mArray1 retain]; NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
-
2014-06-17 10:41:45.092 TicketProject[799:907] mArray1 retain count: 1 2014-06-17 10:41:45.093 TicketProject[799:907] mArray1 retain count: 2 2014-06-17 10:41:45.093 TicketProject[799:907] mArray1 retain count: 2 2014-06-17 10:41:48.521 TicketProject[799:907] mArray1 retain count: 3
->copy 与mutableCopy浅谈 - 1. 系统的非容器类对象
这里指的是NSString,NSNumber等等一类的对象。
NSString *string = @"origion";
NSString *stringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];
[stringMCopy appendString:@"!!"];
查看内存可以发现,string和stringCopy指向的是同一块内存区域(又叫apple弱引用weak reference), - 此时stringCopy的引用计数和string的一样都为2。而stringMCopy则是我们所说的真正意义上的复制,系统为其分配了新内存,但指针所指向的字符串还是和string所指的一样。
再看下面的例子:
NSMutableString *string = [NSMutableString stringWithString: @"origion"];
NSString *stringCopy = [string copy];
NSMutableString *mStringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];
[mStringCopy appendString:@"mm"];//error
[string appendString:@" origion!"];
[stringMCopy appendString:@"!!"];
以上四个NSString对象所分配的内存都是不一样的。但是对于mStringCopy其实是个imutable对象,所以上述会报错。
对于系统的非容器类对象,我们可以认为,如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。 - 如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
2. 系统的容器类对象
指NSArray,NSDictionary等。对于容器类本身,上面讨论的结论也是适用的,需要探讨的是复制后容器内对象的变化。
//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]);1
NSLog(@"array1 retain count: %d",[arrayCopy1 retainCount]);2
NSMutableArray *mArrayCopy1 = [array1 mutableCopy];
//mArrayCopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的是同一个对象。- mArrayCopy1还可以修改自己的对象
[mArrayCopy1 addObject:@"de"]; Printing description of mArrayCopy1: <__NSArrayM 0x95e5e40>( a, b, c, de )
[mArrayCopy1 removeObjectAtIndex:0];
Printing description of mArrayCopy1: <__NSArrayM 0x95a97b0>( b, c, de )
array1和arrayCopy1是指针复制,而mArrayCopy1是对象复制,mArrayCopy1还可以改变期内的元素:删除或添加。- 但是注意的是,容器内的元素内容都是指针复制。
下面用另一个例子来测试一下。
NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *mArrayCopy2 = [mArray1 copy];- NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);2
NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];
NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);2
//mArrayCopy2,mArrayMCopy1和mArray1指向的都是不一样的对象,但是其中的元素都是一样的对象——同一个指针
//一下做测试
NSMutableString *testString = [mArray1 objectAtIndex:0];
[testString appendString:@" tail"];//这样以上三个数组的首元素都被改变了TicketProject[975:907] mArrayMCopy2:( "a tail", b, c ) 2014-06-17 11:26:20.624 TicketProject[975:907] mArrayMCopy1:( "a tail", b, c ) 2014-06-17 11:26:21.599 TicketProject[975:907] mArrayMCopy2:( "a tail", b, c )
- 由此可见,对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝。http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html
NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"first"],[NSStringstringWithString:@"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]和[[deepCopyArray objectAtIndex:0]尽管是指向同一块内存,但是我们没有办法对其进行修改——因为它是不可改变的。所以指针复制已经足够。所以这并不是完全意义上的深拷贝,但是apple的官方文档将其列为deep copy了,并添加了copy和mutablity的关系说明,故在此做一说明(这边还有点疑惑,有了解的赐教啊)。
-