詳解iOS的深淺拷貝
前言
OC對象的三種拷貝方式
OC的對象拷貝有如下三種方式,很多時候我們把深復(fù)制和完全復(fù)制混為一談,其他他們是有區(qū)別的,具體如下
淺復(fù)制(shallow copy):在淺復(fù)制操作時,對于被復(fù)制對象的每一層都是指針復(fù)制。
深復(fù)制(one-level-deep copy):在深復(fù)制操作時,對于被復(fù)制對象,至少有一層是深復(fù)制。
完全復(fù)制(real-deep copy):在完全復(fù)制操作時,對于被復(fù)制對象的每一層都是對象復(fù)制。
兩圖以避之
理解深復(fù)制(mutableCopy)
淺復(fù)制很簡單,就不演示了,看上面的圖就懂了,只是簡單的指針拷貝,所以改變原對象或者拷貝后的對象,都會影響另外一個對象。
從上圖我們可以看到mutableCopy
對于任何對象都是內(nèi)容復(fù)制,也就是說進行了深復(fù)制。
上代碼:
NSMutableArray * dataArray1=[NSMutableArray arrayWithObjects: [NSMutableString stringWithString:@"1"], [NSMutableString stringWithString:@"2"], [NSMutableString stringWithString:@"3"], [NSMutableString stringWithString:@"4"], nil ]; NSMutableArray * dataArray2=[NSMutableArray arrayWithObjects: [NSMutableString stringWithString:@"one"], [NSMutableString stringWithString:@"two"], [NSMutableString stringWithString:@"three"], [NSMutableString stringWithString:@"four"], dataArray1, nil ]; NSMutableArray * dataArray3; NSMutableString * mStr; dataArray3=[dataArray2 mutableCopy]; mStr = dataArray2[0]; [mStr appendString:@"--ONE"]; NSLog(@"dataArray3:%@",dataArray3); NSLog(@"dataArray2:%@",dataArray2);
輸出如下:
2016-07-31 17:40:30.702 test1[2113:169774] dataArray3:( "one--ONE", two, three, four, ( 1, 2, 3, 4 ) ) 2016-07-31 17:40:30.703 test1[2113:169774] dataArray2:( "one--ONE", two, three, four, ( 1, 2, 3, 4 ) )
看上面的輸出,我們發(fā)現(xiàn)我們改變原數(shù)組dataArray2
,竟然也會影響深復(fù)制后的dataArray3
,不是說好的內(nèi)容復(fù)制嗎,為什么會這樣?
這里我們來說說深復(fù)制和完全復(fù)制的區(qū)別。
我們知道深復(fù)制,就是把原有對象的內(nèi)容直接克隆一份到新對象,但是這里有一個坑就是他只會復(fù)制一層對象,而不會復(fù)制第二層甚至更深層次的對象。
代碼dataArray3=[dataArray2 mutableCopy];
只是對數(shù)組dataArray2
本身進行了內(nèi)容拷貝,但是里面的字符串對象卻沒有進行內(nèi)容拷貝,而是進行的淺復(fù)制,那么dataArray2
和dataArray3
里面的對象是共享同一份的。所以才會出現(xiàn)上面的情況。
單層深復(fù)制
那么如何解決上面的問題呢?
可以使用如下代碼
dataArray3=[[NSMutableArray alloc]initWithArray:dataArray2 copyItems:YES];
輸出如下:
2016-07-31 17:45:48.472 test1[2151:173221] dataArray3:( one, two, three, four, ( 1, 2, 3, 4 ) ) 2016-07-31 17:45:48.472 test1[2151:173221] dataArray2:( "one--ONE", two, three, four, ( 1, 2, 3, 4 ) )
可以看到dataArray3
并沒有被改變,但是別高興的太早,我們再來改改。
代碼如下:
NSMutableArray * dataArray1=[NSMutableArray arrayWithObjects: [NSMutableString stringWithString:@"1"], [NSMutableString stringWithString:@"2"], [NSMutableString stringWithString:@"3"], [NSMutableString stringWithString:@"4"], nil ]; NSMutableArray * dataArray2=[NSMutableArray arrayWithObjects: [NSMutableString stringWithString:@"one"], [NSMutableString stringWithString:@"two"], [NSMutableString stringWithString:@"three"], [NSMutableString stringWithString:@"four"], dataArray1, nil ]; NSMutableArray * dataArray3; NSMutableString * mStr; dataArray3=[[NSMutableArray alloc]initWithArray:dataArray2 copyItems:YES]; NSMutableArray *mArr = (NSMutableArray *)dataArray2[4]; mStr = mArr[0]; [mStr appendString:@"--ONE"]; NSLog(@"dataArray3:%@",dataArray3); NSLog(@"dataArray2:%@",dataArray2);
輸出如下:
2016-07-31 17:47:19.421 test1[2174:174714] dataArray3:( one, two, three, four, ( "1--ONE", 2, 3, 4 ) ) 2016-07-31 17:47:19.421 test1[2174:174714] dataArray2:( one, two, three, four, ( "1--ONE", 2, 3, 4 ) )
可以看到深復(fù)制又失效了,這是因為dataArray3=[[NSMutableArray alloc]initWithArray:dataArray2 copyItems:YES];
僅僅能進行一層深復(fù)制,對于第二層或者更多層的就無效了,那怎么辦呢?
別急,我們還有大招沒放。
完全復(fù)制
要想對多層集合對象進行復(fù)制,我們需要進行完全復(fù)制,這里可以使用歸檔和接檔。
實現(xiàn)代碼如下:
dataArray3 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:dataArray2]];
此時輸出如下:
2016-07-31 17:49:55.561 test1[2202:177163] dataArray3:( one, two, three, four, ( 1, 2, 3, 4 ) ) 2016-07-31 17:49:55.562 test1[2202:177163] dataArray2:( one, two, three, four, ( "1--ONE", 2, 3, 4 ) )
可以看到dataArray3
沒有被dataArray2
的修改影響。
類復(fù)制
說完了對象的復(fù)制,我們來看看如何實現(xiàn)類的復(fù)制,因為比較簡單,直接放上代碼
定義類復(fù)制
#import <Foundation/Foundation.h> @interface Person : NSObject<NSCopying> @property(strong,nonatomic)NSString *age; @property(strong,nonatomic)NSString *name; @end
#import "Person.h" @implementation Person - (id)copyWithZone:(NSZone *)zone { Person *person = [[Person allocWithZone:zone] init]; person.age = self.age; person.name = self.name; return person; } @end
調(diào)用
Person *person = [[Person alloc]init]; person.age = @"dsdsd"; person.name = @"dsdsdddww"; Person *copyPerson = [person copy]; NSLog(@"%@-----%@",copyPerson.age, copyPerson.name);
可以看到copyPerson
的兩個屬性和persona
一樣。
@property中的copy關(guān)鍵字
在設(shè)置NSString類型的屬性的時候,我們最好設(shè)置為copy類型,這樣別人使用我們定義的屬性的時候,他不管怎么改動該屬性的賦值,都不會影響我們給該屬性賦的值,為什么呢?
下面我們來看看
如上圖所示,string2
的屬性是copy
類型,可以看到是無法被修改的。
因為此時string2
和copystring
的內(nèi)存地址不一樣,修改一個,不會影響另外一個。
上圖所示,如果string2
的屬性是strong
類型,就可以被修改,如下圖所示:
因為此時string2
和copystring
的內(nèi)存地址都是一樣的,修改一個,兩個就同時被修改
copy關(guān)鍵字的NSMutableString崩潰
原因:
copy
關(guān)鍵字的string
的setter
方法實際上是把參數(shù)copy之后再賦值給變量_string
,那么此時變量_string
雖然被申明為NSMutableString
,但是copy
之后,就把 變量_string
變成了不可變的NSString
類型,所以就會出現(xiàn)方法報錯,提示對不可變的NSString
使用了NSMutableString
的方法appendString
。
總結(jié)
以上就是iOS的深淺拷貝的詳細內(nèi)容,希望本文在大家開發(fā)iOS的過程中能有所幫助。
相關(guān)文章
iOS開發(fā)中UITableview控件的基本使用及性能優(yōu)化方法
這篇文章主要介紹了iOS開發(fā)中UITableview控件的基本使用及性能優(yōu)化方法,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2015-12-12