在最開始,我們需要清楚一些關於記憶體分配方式的基礎知識。 一般來說分為棧、堆、靜態變數存儲區、全局變數存儲區、代碼區。 前兩個大家都懂的。通常將後三個合併稱之為靜態存儲區,存儲的是一些全局變數、靜態變數、常量、執行代碼等。 在Objective-C中,不可變數組、不可變字典以及一些常量字元串,都是分配
在最開始,我們需要清楚一些關於記憶體分配方式的基礎知識。
一般來說分為棧、堆、靜態變數存儲區、全局變數存儲區、代碼區。
前兩個大家都懂的。通常將後三個合併稱之為靜態存儲區,存儲的是一些全局變數、靜態變數、常量、執行代碼等。
在Objective-C中,不可變數組、不可變字典以及一些常量字元串,都是分配在這個區域的,我們先要明確這一點。
所以在提到深淺拷貝的時候,用NSArray舉例子的,只能說對記憶體分配方式就不清楚,因為對一個不可變數組進行copy操作,它實際上返回的是一個對象,跟深淺拷貝無關,因為都是按照retain來處理的。這也就是很多所謂教程提到的指針拷貝。
下麵先說一下可變拷貝和不可變拷貝,分別遵循NSCopying和NSMutableCopying協議,需要對應實現copyWithZone:方法和mutableCopyWithZone:方法。
分兩種情況來講,一種是系統容器類,一種是自定義類。
一、系統容器類。
例如NSArray、NSDictionary,它們已經實現了上面兩個協議。
對於它們來說,規則很簡單,obj2 = [obj1 copy]返回的必然是一個不可變對象,無論obj1是可變對象還是不可變對象。如果obj1是一個不可變對象,那麼它們指向同一個對象,也是上一條我提到過的。
obj2 = [obj1 mutableCopy]返回的必然是一個可變對象,無論obj1是可變對象還是不可變對象。即使obj1也是一個可變對象,它們仍指向不同地址,是兩個對象。
二、自定義類。
因為copyWithZone:和mutableCopyWithZone:完全由自己來實現,所以代碼的不同實現方式,決定了返回對象是什麼。
在demo中Element類的copyWithZone:有註釋,感興趣的可以參考一下。
極端一點的例子,例如你直接在copyWithZone:方法中return self;那麼obj2 = [obj1 copy]相當於obj2 = obj1,只是一個assign,沒有做任何其它操作。
下麵著重說一下淺拷貝和深拷貝。
首先顧名思義,無論是淺拷貝還是深拷貝,都有一個拷貝在裡面,那些說淺拷貝相當於retain、什麼所謂指針拷貝的,建議還是不要誤人子弟了好吧。
這裡我們以NSMutableArray為例
NSMutableArray *element = [NSMutableArray arrayWithObject:@1];
NSMutableArray *array = [NSMutableArray arrayWithObject:element];
id mutableCopyArray = [array mutableCopy];
這一句代碼就是淺拷貝,是拷貝了容器自身,返回了一個新的可變數組,指向不同的記憶體地址。
內部的元素依然是公用的,也就是說,mutableCopyArray[0]也指向element,[mutableCopyArray[0] addObject:***]會影響到array的結果。
id deepMutableCopyArray = [array test_deepMutableCopy];
這一句代碼對應的實現是深拷貝,首先它也拷貝了容器自身,返回了一個新的可變數組,指向不同的記憶體地址。
其次,對內部的元素也進行了拷貝動作,也就是說deepMutableCopyArray[0]是一個新的可變數組,和原來的element是兩個數組,修改[deepMutableCopyArray[0] addObject:***]並不會影響到array的結果。