首先提出一個問題
@property聲明的NSString(或NSArray,NSDictionary),為什么經(jīng)常使用copy關鍵字?改成strong關鍵字,會有什么問題?
1.因為父類指針可以指向子類對象,使用 copy 的目的是為了讓本對象的屬性不受外界影響,使用 copy 無論給我傳入是一個可變對象還是不可對象,我本身持有的就是一個不可變的副本.
2.如果我們使用是 strong ,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性.
copy 此特質(zhì)所表達的所屬關系與 strong 類似。然而設置方法并不保留新值,而是將其“拷貝” (copy)。 當屬性類型為 NSString 時,經(jīng)常用此特質(zhì)來保護其封裝性,因為傳遞給設置方法的新值有可能指向一個 NSMutableString 類的實例。這個類是 NSString 的子類,表示一種可修改其值的字符串,此時若是不拷貝字符串,那么設置完屬性之后,字符串的值就可能會在對象不知情的情況下遭人更改。所以,這時就要拷貝一份“不可變” (immutable)的字符串,確保對象中的字符串值不會無意間變動。只要實現(xiàn)屬性所用的對象是“可變的” (mutable),就應該在設置新屬性值時拷貝一份。
舉例說明:
定義一個strong修飾的array:
@property (nonatomic ,readwrite, strong) NSArray *array;
然后:
NSArray *array = @[ @1, @2, @3, @4 ];
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array];
self.array = mutableArray;
[mutableArray removeAllObjects];;
NSLog(@"%@",self.array);
[mutableArray addObjectsFromArray:array];
self.array = [mutableArray copy];
[mutableArray removeAllObjects];
NSLog(@"%@",self.array);
打?。?/p>
2015-09-27 19:10:32.523 CYLArrayCopyDmo[10681:713670] {
}
2015-09-27 19:10:32.524 CYLArrayCopyDmo[10681:713670] {
1,
2,
3,
4
}
由此引出一下兩種情況
- 對非集合類對象的copy與mutableCopy操作;
- 對集合類對象的copy與mutableCopy操作;
1.對非集合類對象的Copy操作:
在非集合類對象中:對 immutable 對象進行 copy 操作,是指針復制,mutableCopy 操作時內(nèi)容復制;對 mutable 對象進行 copy 和 mutableCopy 都是內(nèi)容復制。用代碼簡單表示如下:
- [immutableObject copy];//淺拷貝
- [immutableObject mutableCopy];深拷貝
- [mutableObject copy];//深拷貝
- [mutableObject mutableCopy];//深拷貝
例如:
NSMutableString *string = [NSMutableString stringWithString:@"origin"];//copy
NSString *stringCopy = [string copy];
查看內(nèi)存,會發(fā)現(xiàn) string、stringCopy 內(nèi)存地址都不一樣,說明此時都是做內(nèi)容拷貝、深拷貝。
即使你進行如下操作:
[string appendString:@"origion!"]
stringCopy 的值也不會因此改變,但是如果不使用 copy,stringCopy 的值就會被改變。 集合類對象以此類推。
所以:
用 @property 聲明 NSString、NSArray、NSDictionary 經(jīng)常使用 copy 關鍵字,是因為他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary,他們之間可能進行賦值操作,為確保對象中的字符串值不會無意間變動,應該在設置新屬性值時拷貝一份。
2.集合類對象的copy與mutableCopy
集合類對象是指 NSArray、NSDictionary、NSSet ... 之類的對象。下面先看集合類immutable對象使用 copy 和 mutableCopy 的一個例子:
NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"]];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];
查看內(nèi)容,可以看到 copyArray 和 array 的地址是一樣的,而 mCopyArray 和 array 的地址是不同的。說明 copy 操作進行了指針拷貝,mutableCopy 進行了內(nèi)容拷貝。但需要強調(diào)的是:此處的內(nèi)容拷貝,僅僅是拷貝 array 這個對象,array 集合內(nèi)部的元素仍然是指針拷貝。這和上面的非集合 immutable 對象的拷貝還是挺相似的,那么mutable對象的拷貝會不會類似呢?我們繼續(xù)往下,看 mutable 對象拷貝的例子:
NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];
查看內(nèi)存,如我們所料,copyArray、mCopyArray和 array 的內(nèi)存地址都不一樣,說明 copyArray、mCopyArray 都對 array 進行了內(nèi)容拷貝。
同樣,我們可以得出結(jié)論:
在集合類對象中,對 immutable 對象進行 copy,是指針復制, mutableCopy 是內(nèi)容復制;對 mutable 對象進行 copy 和 mutableCopy 都是內(nèi)容復制。但是:集合對象的內(nèi)容復制僅限于對象本身,對象元素仍然是指針復制.
用代碼簡單表示如下:
[immutableObject copy] // 淺復制
[immutableObject mutableCopy] //單層深復制
[mutableObject copy] //單層深復制
[mutableObject mutableCopy] //單層深復制
這個代碼結(jié)論和非集合類的非常相似。
--
集合的淺復制(shallow Copy)
集合的淺復制有非常多種方法。當你進行淺復制時,會向原始的集合發(fā)送retain消息,引用計數(shù)加1,同時指針被拷貝到新的集合。
看一些淺復制的例子:
NSArray *shallowCopyArray = [someArray copyWithZone:nil];
NSSet *shallowCopySet = [NSSet mutableCopyWithZone:nil];
NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:NO];
集合的深復制(deep copy)
集合的深復制有兩種方法。
- 1.可以用initWithArray:copyItems: 將第二個參數(shù)設置為YES即可深復制
如:
NSDictionary shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:YES];
如果你用這種方法深復制,集合里的每個對象都會收到 copyWithZone: 消息。如果集合里的對象遵循 NSCopying 協(xié)議,那么對象就會被深復制到新的集合。如果對象沒有遵循 NSCopying 協(xié)議,而嘗試用這種方法進行深復制,會在運行時出錯。copyWithZone: 這種拷貝方式只能夠提供一層內(nèi)存拷貝(one-level-deep copy),而非真正的深復制。
- 2.第二個方法是將集合進行歸檔(archive),然后解檔(unarchive).
NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];