什麼叫做copy/mutableCopy?如何實現淺/深拷貝?
什麼叫做copy:利用原物件產生一個副本物件,(副本物件中的內容和原物件內容一致)修改原物件的屬性和行為不會影響副本物件,修改副本物件不會影響原物件。
-
一般情況下copy/mutableCopy操作會生成一個新的物件,但是不可變物件通過copy不會生成新物件。
- 產生新物件的原因:
- 修改原物件不會影響副本物件,修改副本物件不會影響原物件。
- 不可變物件通過mutableCopy生成可變物件,所以必須生成新物件(可變物件通過copy生成不可變物件同理)。
- 可變物件通過mutableCopy生成可變物件,當修改原/副本物件的時候不能相互影響所以要生成新物件。
- 不可變物件通過copy生成不可變物件,因為兩個物件是都不能修改的,所以不會生成新物件(oc的記憶體優化)。
-
注意:
``` [NSArray mutableCopy] -> NSMutableArray [NSMutableArray copy] -> NSArray ```
- 產生新物件的原因:
-
正因為copy有時會生成新物件,有時不會生成新物件,所以就出現了淺拷貝與深拷貝
- 淺拷貝:沒有生成新物件,本質就是指標拷貝。
- 注意:
原物件引用計數+1(相當於進行retain操作)。
- 注意:
- 深拷貝:生成新物件,本質就是建立了一個新物件。
- 注意:原物件引用計數不變。
- 淺拷貝:沒有生成新物件,本質就是指標拷貝。
如果想令自己的類支援拷貝操作就要實現NSCopying或NSMutableCopying協議。如果自定義的物件分為可變和不可變兩個版本,就要同時實現NSCopying和NSMutableCopying協議。
-
NSCopying協議中只有一個方法(生成不可變物件)
``` - (id)copyWithZone:(nullable NSZone *)zone; ```
舉例實現:
``` //Person.h @property (nonatomic, assign) int age; @property (nonatomic, copy) NSString *name; //Person.m - (id)copyWithZone:(NSZone *)zone { // 1.建立一個新的物件 Person *p = [[[self class] allocWithZone:zone] init]; // 2.設定當前物件的內容給新的物件 p.age = _age; p.name = _name; // 3.返回新的物件 return p; } ```
-
NSMutableCopying協議中只有一個方法(生成可變物件)
``` - (id)mutableCopyWithZone:(nullable NSZone *)zone; ``` 舉例實現: ``` //Person.h @property (nonatomic, assign) int age; @property (nonatomic, copy) NSString *name; //Person.m - (id)mutableCopyWithZone:(NSZone *)zone { // 1.建立一個新的物件 Person *p = [[[self class] allocWithZone:zone] init]; // 2.設定當前物件的內容給新的物件 p.age = _age; p.name = _name; // 3.返回新的物件 return p; } ```
-
淺拷貝:只拷貝容器物件本身,而不復制其中的資料。
``` //Person.h @property (nonatomic, assign) int age; @property (nonatomic, copy) NSString *name; //Person.m - (id)copyWithZone:(NSZone *)zone { // 1.建立一個新的物件 Person *p = self; // 2.返回新的物件 return p; } ```
-
深拷貝:在拷貝物件自身的時候,將底層資料也複製過去。
``` //Person.h @property (nonatomic, assign) int age; @property (nonatomic, copy) NSString *name; //Person.m - (id)deepCopy { // 1.建立一個新的物件 Person *p = [[[self class] allocWithZone:zone] init]; // 2.設定當前物件的內容給新的物件 p.age = _age; p.name = _name; // 3.返回新的物件 return p; } ```
複製物件的時候一般執行淺拷貝。
如果你的物件需要深拷貝,應該考慮專門執行深拷貝的方法。
字串屬性都要使用copy。(防止外界修改內部資料)
-
使用copy儲存block,這樣可以保住block中使用的外界物件,避免以後呼叫block的時候,物件已經被外界釋放。(Block_release(blcok),MRC中使用,釋放block,並且block中的物件也可以接收到release訊息)
- 注意:copy block之後會產生迴圈引用(物件中的block又用到了物件自己),為了避免記憶體洩漏應該講物件修飾為__block.
-
子類會繼承父類的協議,當父類實現了copy的方法,子類也就相應的實現了。但是如果子類有新的屬性,那麼必須在子類中重寫copyWithZone方法, 在該方法中先呼叫父類建立副本設定值, 然後再設定子類特有的值。
-
舉例(Son為上文中Person的子類)
Son.h @property (nonatomic, assign) double height; Son.m - (id)copyWithZone:(NSZone *)zone { // 1.建立一個新的物件 id obj = [super copyWithZone:zone]; // 2.設定新物件的資料 [obj setHeight:_height]; // 3.返回新物件 return obj; } ```
-
相關文章
- 深、淺拷貝deepcopy()和copy()
- 深拷貝和淺拷貝的區別是什麼?實現一個深拷貝
- 實現物件淺拷貝、深拷貝物件
- [JS系列二]談談深拷貝和淺拷貝,如何實現深拷貝JS
- 淺拷貝與深拷貝的實現
- js實現深拷貝和淺拷貝JS
- 前端JS:什麼是深拷貝?什麼是淺拷貝?前端JS
- 【JS】深拷貝與淺拷貝,實現深拷貝的幾種方法JS
- 淺拷貝&深拷貝
- js物件實現深淺拷貝!!JS物件
- 淺談深拷貝與淺拷貝?深拷貝幾種方法。
- 淺拷貝與深拷貝
- 淺拷貝和深拷貝
- 深拷貝和淺拷貝
- java深克隆(深拷貝)和淺克隆(淺拷貝)Java
- 深拷貝和淺拷貝 copy與strong修飾變數的區別變數
- JS中的深淺拷貝以及實現深拷貝的幾種方法.JS
- 怎麼實現深拷貝
- Java深拷貝和淺拷貝Java
- Python淺拷貝與深拷貝Python
- 物件深拷貝和淺拷貝物件
- JavaScript深拷貝和淺拷貝JavaScript
- javascript 淺拷貝VS深拷貝JavaScript
- js 淺拷貝和深拷貝JS
- JS深拷貝與淺拷貝JS
- iOS深拷貝和淺拷貝iOS
- python深拷貝與淺拷貝Python
- js 深拷貝和淺拷貝JS
- JavaScript淺拷貝和深拷貝JavaScript
- 深入淺出深拷貝與淺拷貝
- 淺探js深拷貝和淺拷貝JS
- js 淺拷貝(淺複製、淺克隆)、深拷貝(深複製、深克隆)JS
- 什麼要使用克隆、如何實現克隆物件、序列化與反序列實現克隆的好處、深拷貝與淺拷貝物件
- 深入淺出的“深拷貝與淺拷貝”
- python 指標拷貝,淺拷貝和深拷貝Python指標
- 正則以及淺拷貝深拷貝
- 談談深拷貝與淺拷貝
- 賦值、淺拷貝與深拷貝賦值
- JavaScript之深拷貝和淺拷貝JavaScript