浅拷贝和深拷贝的区别

浅拷贝:

Making a shallow copy:

NSArray *shallowCopyArray = [someArray copyWithZone:nil];

NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:NO];

Deep Copies:这两种方法

If you create a deep copy of a collection in this way, each object in the collection is sent a copyWithZone: message. If the objects in the collection have adopted the NSCopying protocol, the objects are deeply copied to the new collection, which is then the sole owner of the copied objects. If the objects do not adopt the NSCopying protocol, attempting to copy them in such a way results in a runtime error. However, copyWithZone: produces a shallow copy.

Making a deep copy:

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

A true deep copy:

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:

[NSKeyedArchiver archivedDataWithRootObject:oldArray]];

当然在ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutableCopying 协议的类才可以发送mutableCopy消息。假如发送了一个没有遵守上诉两协议而发送 copy或者 mutableCopy,那么就会发生异常。但是默认的ios类并没有遵守这两个协议。如果想自定义一下copy 那么就必须遵守NSCopying,并且实现 copyWithZone: 方法,如果想自定义一下mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法。

id temp = [array objectAtIndex:0];

[array removeObjectAtIndex:0];

如果你再要使用temp就会出错,因为这个时候obj已经被释放了。

由于在程序中经常会遇到集合类的传值,所以,简单的retain未必够用,需要对集合内容的拷贝,也就是深拷贝。

1、  系统的非容器类对象:

这里指的是NSString,NSNumber等等一类的对象。

NSString *string = @"origion";

NSString *stringCopy = [string copy];

NSMutableString *stringMCopy = [string mutableCopy];

再看下面的例子:

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返回的对象是不可变的。


string改变值,copy后的string并不会随着改变,还是原来的值。给string赋值也是一样的结果。

探究propoty声明的对象为strong和copy的区别

这篇文章中属性无论是可变还是不可变的,只要声明为strong,在可变对象赋值给属性后,如果改变可变对象,则属性也会改变。copy则是不改变。还是copy相对安全些。

2、  系统的容器类对象

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

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

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

NSArray *arrayCopy1 = [array1 copy];

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

NSMutableArray *mArrayCopy1 = [array1 mutableCopy];

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

[mArrayCopy1 addObject:@"de"];

[mArrayCopy1 removeObjectAtIndex:0];

array1和arrayCopy1是指针复制,而mArrayCopy1是对象复制,mArrayCopy1还可以改变期内的元素:删除或添加。但是注意的是,容器内的元素内容都是指针复制。

下面用另一个例子来测试一下。

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

NSArray *mArrayCopy2 = [mArray1 copy];

NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];

//mArrayCopy2,mArrayMCopy1和mArray1指向的都是不一样的对象,但是其中的元素都是一样的对象——同一个指针

//一下做测试

NSMutableString *testString = [mArray1 objectAtIndex:0];

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

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

但是里面的元素指针地址都是一样的,无论是哪种拷贝。里面的元素都是浅复制。下面两个方法才是深复制,第二个才是真正意义的深复制。

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html

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内的不可变元素其还是指针复制。或者我们自己实现深拷贝的方法。因为如果容器的某一元素是不可变的,那你复制完后该对象仍旧是不能改变的,因此只需要指针复制即可。除非你对容器内的元素重新赋值,否则指针复制即已足够。

拷贝构造:

当然在 ios 中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying协议的类可以发送copy消息,遵守NSMutableCopying协议的类才可以发送mutableCopy消息。

假如发送了一个没有遵守上诉两协议而发送copy或者 mutableCopy,那么就会发生异常。但是默认的ios类并没有遵守这两个协议。如果想自定义一下copy 那么就必须遵守NSCopying,并且实现 copyWithZone: 方法,如果想自定义一下mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法。

如果是我们定义的对象,那么我们自己要实现NSCopying , NSMutableCopying这样就能调用copy和mutablecopy了。举个例子:

@interface MyObj : NSObject《NSCopying, NSMutableCopying》{

NSMutableString *_name;

NSString * _imutableStr ;

int _age;

}

@property (nonatomic, retain) NSMutableString *name;

@property (nonatomic, retain) NSString *imutableStr;

@property (nonatomic) int age;

copy拷贝构造:

-- (id)copyWithZone:(NSZone *)zone{

MyObj *copy = [[[self class] allocWithZone :zone] init];

copy->name = [_name copy];

copy->imutableStr = [_imutableStr copy];

copy->age = age;

return copy;

}

mutableCopy拷贝构造:

-- (id)mutableCopyWithZone:(NSZone *)zone{

MyObj *copy = NSCopyObject(self, 0, zone);

copy->name = [_name mutableCopy];

copy->age = age;

return copy;

}

http://www.jianshu.com/p/e6a7cdcc705d

注意点:

(1)当使用mutableCopy时,不管源对象是否可变,副本是可变的,并且实现真正意义上的拷贝。

当我们使用copy一个可变对象时,副本对象是不可变的。

(2)要想实现对象的自定义拷贝,必须实现NSCopying,NSMutableCopying协议,实现该协议的copyWithZone方法和mutableCopyWithZone方法。深拷贝和浅拷贝的区别就在于copyWithZone方法的实现。

字符串之所以用copy是因为:

NSMutableString *string1 = [NSMutableString stringWithFormat:@"大家好"];

FatherClass *father = [FatherClass new];

father.name = string1;

// 不能改变person.name的值,因为其内部copy新的对象

[string1 appendString:@" 哈哈"];

如果是copy,则father.name =  @"大家好";

string1 = @"大家好哈哈"。如果是strong,father.name = string1= @"大家好哈哈" ;

深.浅拷贝

copy/mutableCopy NSString

NSString *string= @"汉斯哈哈哈";// 没有产生新对象NSString *copyString = [stringcopy];// 产生新对象NSMutableString *mutableCopyString = [stringmutableCopy];NSLog(@"string = %p copyString = %p mutableCopyString = %p",string, copyString, mutableCopyString);

copy/mutableCopy NSMutableString

NSMutableString*string = [NSMutableStringstringWithString:@"汉斯哈哈哈"];// 产生新对象NSString*copyString = [stringcopy];// 产生新对象NSMutableString*mutableCopyString = [string mutableCopy];NSLog(@"string = %p copyString = %p mutableCopyString = %p", string, copyString, mutableCopyString);

结论:

注意:其他对象NSArray、NSMutableArray 、NSDictionary、NSMutableDictionary一样适用

copy NSObject

HSPerson *p = [[HSPerson alloc] init];p.age =20;p.height =170.0;HSPerson *copyP = [p copy]; // 这里崩溃

崩溃:

看崩溃信息HSPerson应该先实现:

-(id)copyWithZone:(NSZone *)zone;

测试:

#import"HSPerson.h"@interfaceHSPerson()@end@implementationHSPerson- (id)copyWithZone:(NSZone*)zone{return@"汉斯哈哈哈";}@end

HSPerson *p = [[HSPerson alloc] init];p.age =20;p.height =170.0;HSPerson *copyP = [p copy];NSLog(@"copyP: %@", copyP);

可以看出copyWithZone重新分配新的内存空间,则:

- (id)copyWithZone:(NSZone *)zone{    HSPerson *person=[[HSPerson allocWithZone:zone]init];    returnperson;// 有些人可能下面alloc,重新初始化空间,但这方法已给你分配了zone,自己就无需再次alloc内存空间了//    HSPerson *person=[[HSPerson alloc]init];}

HSPerson *p = [[HSPerson alloc] init];p.age =20;p.height =170.0;HSPerson *copyP = [p copy];NSLog(@"p = %p copyP = %p", p, copyP);NSLog(@"age = %d height = %f", copyP.age, copyP.height);

虽然copy了份新的对象,然而age,height值并未copy,那么:

- (id)copyWithZone:(NSZone *)zone{    HSPerson *person=[[HSPerson allocWithZone:zone]init];person.age = self.age;person.height = self.height;    // 这里self其实就要被copy的那个对象,很显然要自己赋值给新对象,所以这里可以控制copy的属性    returnperson;}

这时你会想,有NSMutableCopying?没错,是有这货:

- (id)mutableCopyWithZone:(NSZone *)zone{    HSPerson *person=[[HSPerson allocWithZone:zone]init];person.age = self.age;person.height = self.height;    returnperson;}

NSCopying、NSMutableCopying有啥区别?

其实感觉没必要有NSMutableCopying,因为压根就没可变的HSPerson,但如果该对象有其他行为,可以借用NSMutableCopying实现,哈哈哈

property里的copy、strong区别

说完深浅拷贝,理解property里的copy、strong就轻松多了!

copy

#import@interfaceHSPerson:NSObject@property(nonatomic,copy)NSString*name;@end

NSMutableString *string =[NSMutableString stringWithFormat:@"汉斯哈哈哈"];HSPerson *person=[[HSPerson alloc]init];person.name = string;// 不能改变person.name的值,因为其内部copy新的对象[string appendString:@" hans"]; NSLog(@"name = %@",person.name);

property copy 实际上就对name干了这个:

- (void)setName:(NSString *)name{_name= [namecopy];}

假设name为NSMutableString,会发生什么事?

@property(nonatomic,copy)NSMutableString*name;

这样会挨骂哦,实际上内部还是:

- (void)setName:(NSMutableString *)name{_name= [namecopy];}

copy出来的仍然是不可变字符!如果有人用NSMutableString的方法,就会崩溃:

strong

@property(nonatomic,strong)NSString*name;

NSMutableString *string =[NSMutableString stringWithFormat:@"汉斯哈哈哈"];HSPerson *person=[[HSPerson alloc]init];person.name = string;// 可以改变person.name的值,因为其内部没有生成新的对象[string appendString:@" hans"];NSLog(@"name = %@",person.name);

http://www.jianshu.com/p/e6a7cdcc705d

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容