探究Objective-C 之深浅拷贝
c中的浅拷贝与深拷贝
浅拷贝
c中的浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。如:
浅拷贝只是对对象的简单拷贝,让几个对象共用同一片内存,当内存销毁时,指向这片内存的几个指针需要重新定义才可以使用,要不然成为野指针。
深拷贝
c中的深拷贝是指拷贝对象的内容也重新分配一块地址,两个对象也互不影响、互不干涉。如:
深拷贝
|
|
###NSString、NSMutableString对象
NSString对象的retain非常特殊。具体可参考:Objective-C中NSString对象retainCount之谜探索
总结起来是:
@式
123NSString *s = @"t";NSLog(@"s:%lx",[s retainCount]);//输出值为0xffffffffffffffff(UINT_MAX, 2147483647)NSLog(@"s:%ld",[s retainCount]);//输出值-1,由于0xffffffffffffffff补码表示的值为-1s指向的是字符串常量(类似于c语言中的静态区存储),系统不做引用计数,任何retain\release操作,其retainCount值都为UINT_MAX。
stringWithFormat
12NSString *s = [NSString stringWithFormat:@"%s", "test"];NSLog(@"s:%d",[s retainCount]); //输出值为1系统会正常使用引用计数,和普通对象一样;
stringWithString
取决于后面的string对象;
1)12NSString *s1 = [NSString stringWithString:@"test"];NSLog(@"s1:%d",[s1 retainCount]); // 2147483647如“test”为常量,则s1也指向常量,retain为UINT_MAX;
2)123NSString *s2 = [NSString stringWithString:[NSString stringWithFormat:@"test,%d",1]];NSLog(@"s2:%d",[s2 retainCount]); // 2如先用stringWithFormat生成了一个变量,retain为1,再用stringWithString,retain增为2.NSMutableString
1NSMutableString* myStr3 = [NSMutableString stringWithString:@"string 3"]; // 1使用stringWithString,正常计数。
因此 这里只对使用stringWithFormat式创建的对象的copy/mutblecopy行为进行研究。
- 使用copy,无论source\dest对象是否为mutable,都会退化为immutable;且执行的是浅拷贝,指向同一个老的对象, retain数+1;
- 使用mutablecopy,只有在source和dest都为NSMutableString时,可正常使用;且执行的是深拷贝,生成新对象,retain数为1。
iOS其他对象的深浅拷贝
NSCopying
iOS中的immutable对象实现的是NSCopying协议,苹果官网:NSCopying 讲的非常清楚,
在实现该协议的copyWithZone方法时, 不同情况下有不同的实现方式,导致的retain数变化也不定相同:
- 若没有实现过copyWithZone, 则可直接使用alloc和init创建新对象;
- 若该类继承的父类实现了copyWithZone方法,则需overwrite该方法,先调用父类的该方法,再对新增的变量赋值;
- 若为immutable对象,则直接retain+1,返回原始对象;(如同NSString)
例如:
|
|
这里使用了类方法 + (id) allocWithZone: (NSZone *) zone;
,这个消息将被发送到类,而不是实例。 这里使用了[self class]
而不是Tire
,是因为拷贝时,如果是给其子类发送消息,则将无法拷贝其子类的完整信息。
这里调用了initWithPressure:treadDepth:
方法,也可以先调用init
,再手动赋值:
对于子类,其实现Copying的例子如下:
因为AllWeatherRadial继承自一个已实现NSCopying的父类,因此.h里不必再做<NSCopying>
协议声明,而且.m中也没有使用之前的[[self class]allocWithZone]方法,而是使用了父类的copyWithZone方法,由于该方法返回的[self class]类型,因此符合AllWeatherRadial。之后,手动给新添加的属性赋值。
NSMutableCopying
对于mutable对象,实现的是NSMutableCopying协议,苹果官网NSMutableCopying。
如果该类的父类实现了mutableCopyWithZone:方法, 则需要重写该方法,先调用父类的该方法,再对新增的变量赋值;