天天看點

copy與mutableCopy 記住:

記住:

1.對于容器類本身,與非容器類對象的結論相同,即

如果對一不可變對象複制,copy是指針複制(淺拷貝)和mutableCopy就是對象複制(深拷貝)。

如果是對可變對象複制,都是深拷貝,但是copy傳回的對象是不可變的。

關鍵要注意的是複制後容器内對象的變化,比如添加、删除元素,修改某個元素的值。

2.對于容器而言,其元素對象始終是指針複制。如果需要元素對象也是對象複制,就需要實作深拷貝。

開發中經常遇到這個問題,不過發現網上能完整的總結的還是很少。今天就動筆把這個以我的角度總結一下。盡量把問題說明白。。

(一)關于copy和mutableCopy

顧名思義,copy就是複制了一個imutable的對象,而mutablecopy就是複制了一個mutable的對象。

一個NSObject的對象要想使用這兩個函數,那麼類必須實作NSCopying協定和NSMutableCopying協定。

對于NSCopying,實作+ copyWithZone:方法。

對于NSMutableCopying,實作+ mutableCopyWithZone:方法。

當然這種情況一般是在自定義結構體時會用,這個我會在後面舉例說一下。但經常用的NSString,NSArray,NSDictionary等系統提供的結構體都已實作。

(二)NSString、NSMutableString、NSArray、NSMutableArray分别進行copy和mutableCopy時的情況

上面所說的四種結構體可以分為兩種類型。

1.系統的非容器類對象

這裡指的是NSString,NSNumber等等一類的對象。

2.系統的容器類對象

指NSArray,NSDictionary等。

下面對這4種結構體分别進行舉例,分為8總情況。我會配上相應的記憶體截圖。以友善閱讀。

例1:對NSString進行copy和mutableCopy操作

NSString *originStr = @"origin";
NSString *originStrCopy = [originStr copy];
NSMutableString *originStrMutableCopy = [originStr mutableCopy];
           

記憶體截圖:

copy與mutableCopy 記住:

例2:對NSMutableString進行copy和mutableCopy操作

NSMutableString *mutableOriginStr =[NSMutableString stringWithString: @"mutableOrigin"];
//注意這裡下面兩行代碼前面的聲明
NSString *mutableOriginStrCopy = [mutableOriginStr copy];
NSMutableString *mutableOriginStrCopy1 = [mutableOriginStr copy];
//這裡會報錯,因為copy生成的是imutable對象,是以不管聲明是什麼樣的,依舊是imutable的
[mutableOriginStrCopy1 appendString:@"error"];
NSMutableString *mutableOriginStrMutableCopy = [mutableOriginStr mutableCopy];
           

記憶體截圖:

copy與mutableCopy 記住:

總結:

對于系統的非容器類對象,

如果對一不可變對象複制,copy是指針複制(淺拷貝)和mutableCopy就是對象複制(深拷貝)。

如果是對可變對象複制,都是深拷貝,但是copy傳回的對象是不可變的。

例3:對NSArray進行copy和mutableCopy操作

NSArray *originArray = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
NSArray *originArrayCopy = [originArray copy];
//originArray是和originArray同一個NSArray對象(指向相同的對象),包括originArray裡面的元素也是指向相同的指針,此處可以看到copy的作用也相當于retain
NSLog(@"originArray retain count: %ld",(unsigned long)[originArray retainCount]);
NSLog(@"originArray retain count: %ld",(unsigned long)[originArrayCopy retainCount]);
NSMutableArray *originArrayMutableCopy = [originArray mutableCopy];
//originArrayMutableCopy是originArray的可變副本,指向的對象和originArray不同,但是其中的元素和originArray中的元素指向的是同一個對象。originArrayMutableCopy還可以修改自己的對象
[originArrayMutableCopy addObject:@"d"];
[originArrayMutableCopy removeObjectAtIndex:0];
           

記憶體截圖:

1.操作前:

copy與mutableCopy 記住:

2.添加一個元素後:

copy與mutableCopy 記住:

3.删除一個元素後:

copy與mutableCopy 記住:

不知我的xcode怎麼回事,對于originArrayMutableCopy顯示貌似有點問題,打出來結果如下:

2013-03-21 16:08:08.885 MemoryTest[52329:303] originArrayMutableCopy (
    b,
    c,
    d
)
           

總結:

originArray和originArrayCopy是指針複制,而originArrayMutableCopy是對象複制,originArrayMutableCopy還可以改變期内的元素:删除或添加。但是注意的是,容器内的元素内容都是指針複制。

例4:修改元素的值

NSArray *originArray = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"], @"b", @"c", nil];
NSArray *originArrayCopyArray = [originArray copy];
NSMutableArray *originArrayMutableCopyArray = [originArray mutableCopy];
// originArrayMutableCopyArray,originArrayCopyArray和originArray其中的元素都是一樣的對象——同一個指針
//注意:這裡隻能是将值先取出來通過append來修改,如果用testString = @"d";這樣會改變testString的指針,其實是将@“d”臨時對象賦給了testString
NSMutableString *testString = [originArray objectAtIndex:0];
[testString appendString:@" changevalue"];// 這樣以上三個數組的首元素都被改變了
           

記憶體截圖

1.修改值之前

copy與mutableCopy 記住:

2.修改值之後

copy與mutableCopy 記住:

3.用testString = @"d"修改值後記憶體情況,這樣以數組中的元素沒有任何影響,當然也沒有任何意義

copy與mutableCopy 記住:

例5:對NSMutableArray進行copy和mutableCopy操作

NSMutableArray *originArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"c", nil];
NSArray *originArrayCopy = [originArray copy];
NSMutableArray *originArrayCopy1 = [originArray copy];
[originArrayCopy1 addObject:@"d"];//mutable對象copy之後成為imutable對象,是以添加元素會error
 NSMutableArray *originArrayMutableCopy = [originArray mutableCopy];
           

記憶體截圖

copy與mutableCopy 記住:

總結:

1.對于容器類本身,與非容器類對象的結論相同,即

如果對一不可變對象複制,copy是指針複制(淺拷貝)和mutableCopy就是對象複制(深拷貝)。

如果是對可變對象複制,都是深拷貝,但是copy傳回的對象是不可變的。

關鍵要注意的是複制後容器内對象的變化,比如添加、删除元素,修改某個元素的值。

2.對于容器而言,其元素對象始終是指針複制。如果需要元素對象也是對象複制,就需要實作深拷貝。

例6:深拷貝的一種實作

NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],[NSString stringWithString:@"b"],@"c",nil];
NSArray *deepCopyArray=[[NSArray alloc] initWithArray: array copyItems: YES];
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array]];

           

記憶體截圖:

copy與mutableCopy 記住:

總結:

1.trueDeepCopyArray是完全意義上的深拷貝,而deepCopyArray則不是,對于deepCopyArray内的不可變元素其還是指針複制

2.[deepCopyArray objectAtIndex:0]因為原來是可變對象,還和上面的結論一樣,依舊是對象拷貝。

3.用歸檔的方法實作了真正的元素對象拷貝。

4.記得在iphone3開發基礎教程上也有深拷貝的一個方法,下次再總結上來。

繼續閱讀