一直對NSObject的copy方法似懂非懂,今天工做作完了,整理一下html
深複製和淺複製是什麼在這裏就不贅述api
今天主要分三種類型對copy進行探討:系統非容器類對象、系統容器類對象和自定義對象app
NSString *str1 = @"123"; NSString *str2 = [str1 copy]; NSString *str3 = [str1 mutableCopy]; NSMutableString *str4 = [str1 copy]; NSMutableString *str5 = [str1 mutableCopy]; // [str3 appendString:@"456"]; //編譯出錯 // [str4 appendString:@"456"]; //運行出錯
如上代碼,打印結果以下圖ide
結論:atom
1.對比全部string的地址,發現copy返回的是淺複製(只複製了指針),mutableCopy返回的是深複製(從新分配了內存)spa
2.str3在編譯時爲NSString,運行時爲NSMutableString類型,從圖中str3的類型爲__NSCFString可證實,因此修改操做在編譯的時候就會報錯指針
3.str4在編譯時爲NSMutableString,運行時爲NSString類型,從圖中str4的類型爲__NSCFConstantString可證實。因此對str4進行append等修改,編譯可經過,但運行時會直接crashcode
NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"1"], @"2", nil]; NSArray *array2 = [array1 copy]; NSArray *array3 = [array1 mutableCopy]; NSMutableArray *array4 = [array1 copy]; NSMutableArray *array5 = [array1 mutableCopy];
結論:htm
array1-array5的原理同NSString部分,可是注意mutableCopy返回的深複製,是對容器的深複製,容器裏的元素仍然是淺複製對象
NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"1"], @"2", nil]; NSArray *array6 = [[NSArray alloc] initWithArray:array1 copyItems:YES];
此時array6的第一個元素是array1的第一個元素的深複製,可是第二個元素則是淺複製。
莫非用官方的api也會出錯?其實不是的,由於對於不可變對象,對其進行淺複製就足夠,由於你改變不了其值!
因此initWithArray:copyItems:能夠實現一種不夠完全的深複製
NSArray *array7 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array1]];
NSKeyedUnarchiver是真正意義上的深複製
以上,NSString和NSArray都是默認實現了NSCopying和NSMutableCopying協議,才能響應copy和mutableCopy方法
若是是自定義對象,那麼怎麼讓其響應copy和mutableCopy方法呢?
上代碼
// // MyObj.h // No // // Created by Norcy on 16/1/28. // Copyright © 2016年 Norcy. All rights reserved. // #import <Foundation/Foundation.h> @interface MyObj : NSObject<NSCopying, NSMutableCopying> @property (nonatomic, retain) NSMutableString *str1; @property (nonatomic, retain) NSString *str2; @property (nonatomic, assign) int num; @end
// // MyObj.m // No // // Created by Norcy on 16/1/28. // Copyright © 2016年 Norcy. All rights reserved. // #import "MyObj.h" @implementation MyObj - (id)init { if (self = [super init]) { self.str1 = [[NSMutableString alloc] init]; self.str2 = [[NSString alloc] init]; self.num = -1; } return self; } - (id)copyWithZone:(NSZone *)zone { MyObj *obj = [[[self class] allocWithZone:zone] init]; obj.str1 = [self.str1 copyWithZone:zone]; obj.str2 = [self.str2 copyWithZone:zone]; // obj.str1 = [self.str1 copy]; //這樣寫也能夠 // obj.str2 = [self.str2 copy]; obj.num = self.num; return obj; } - (id)mutableCopyWithZone:(NSZone *)zone { MyObj *obj = [[[self class] allocWithZone:zone] init]; obj.str1 = [self.str1 mutableCopyWithZone:zone]; obj.str2 = [self.str2 mutableCopyWithZone:zone]; // obj.str1 = [self.str1 mutableCopy]; //這樣寫也能夠 // obj.str2 = [self.str2 mutableCopy]; obj.num = self.num; return obj; } @end
調用方法以下:
MyObj *obj = [[MyObj alloc] init]; obj.str1 = @"123"; obj.str2 = @"345"; obj.num = 1; MyObj *obj2 = [obj copy]; MyObj *obj3 = [obj mutableCopy];
如上代碼,打印結果以下圖
能夠看到
(1)copy方法準確返回了一個新的對象,且對象的屬性是淺複製
(2)mutableCopy方法準確返回了一個新的對象,且對象的屬性是深複製
(3)想要實現copy方法,須要讓對象聲明遵循<NSCopying>和<NSMutableCopying>協議,而且實現實現copyWithZone:和mutableCopyWithZone:方法
(注意哦,不是實現copy和mutableCopy方法;還有zone參數是什麼鬼?其實zone參數的存在是歷史緣由,如今咱們沒必要太過關心它)
(4)如下這2種寫法在該狀況下是等價的
obj.str1 = [self.str1 copyWithZone:zone]; obj.str2 = [self.str2 copyWithZone:zone];
// obj.str1 = [self.str1 copy]; //這樣寫也能夠 // obj.str2 = [self.str2 copy];
參考文章: