copy關(guān)鍵字和retain關(guān)鍵字
首先說明一個重要的區(qū)別——二者的不同之處在setter方法中揭芍。
- copy關(guān)鍵字:
假如有如下代碼:
@property (nonatomic,copy)NSObject *objA;
NSObject *objB = _objA;
則賦值語句等效于:
[oldValue release];
oldValue = [newValue copy];
這樣可以避免new值變化時影響old值称杨。
- retain關(guān)鍵字:
以下代碼:
@property (nonatomic,retain)NSObject *objA;
NSObject *objB = _objA;
等同于:
[oldValue release];
oldValue = [newValue retain];
一個小tips:一定要把copy屬性關(guān)鍵字用于具有可變子類的不可變對象姑原。
不過悬而,如果對可變對象使用了copy屬性,會如何呢锭汛?來看代碼:(這里我們直接對a進行copy操作笨奠,這和使用copy屬性關(guān)鍵字具有等同的效果)
NSMutableArray *a = [NSMutableArray arrayWithObjects:@0,@1,@2, nil];
NSMutableArray *b = [a copy];
因此,定義可變屬性時不要使用copy關(guān)鍵字店乐,因為在給這個屬性賦值的時候艰躺,該屬性會自動變成不可變類型。如果對該屬性調(diào)用可變類型專有的方法眨八,則會發(fā)生崩潰腺兴。
Block屬性的關(guān)鍵字
因為block在什么時候執(zhí)行是未知的廉侧,所以如果block里外部對象被提前釋放了页响,那么如果這時候block執(zhí)行了,程序就會崩潰段誊。
所以對于Block來說闰蚕,我們一般都用copy關(guān)鍵字修飾.
復(fù)制出的對象的可變性
- 可變對象的復(fù)制:
對可變對象的調(diào)用還是剛剛的代碼,不過我們增加一個變量C來測試:
NSMutableArray *a = [NSMutableArray arrayWithObjects:@0,@1,@2, nil];
NSMutableArray *b = [a copy];
NSMutableArray *c = [a mutableCopy];
打印连舍,得到:
因此没陡,對可變對象調(diào)用copy,得到不可變對象;對可變對象調(diào)用mutableCopy盼玄,得到可變對象贴彼。
-
不可變對象的復(fù)制:
NSArray *a = [NSArray arrayWithObjects:@0,@1,@2, nil]; NSArray *b = [a copy]; NSArray *c = [a mutableCopy];
打印:
因此埃儿,對可變對象調(diào)用copy器仗,得到不可變對象;對可變對象調(diào)用mutableCopy童番,得到可變對象精钮。
淺復(fù)制和深復(fù)制
-
對可變對象進行測試:
NSMutableArray *a = [NSMutableArray arrayWithCapacity:3]; NSMutableArray *b = [a copy]; NSMutableArray *c = [a mutableCopy]; NSLog(@"Address of a:%d",a); NSLog(@"Address of b:%d",b); NSLog(@"Address of c:%d",c);
輸出:
可以看到,三個地址都不一樣剃斧,也就是說轨香,對一個可變類型,無論調(diào)用copy 還是mutableCopy悯衬,都是進行了深復(fù)制跋选。
-
對不可變對象進行測試:
NSArray *a = [NSArray arrayWithObject:@1]; NSMutableArray *b = [a copy]; NSMutableArray *c = [a mutableCopy]; NSLog(@"Address of a:%d",a); NSLog(@"Address of b:%d",b); NSLog(@"Address of c:%d",c);
對可變對象估蹄,copy進行淺復(fù)制,mutableCopy進行深復(fù)制。
集合類復(fù)制的深淺傍睹、可變性問題
剛剛我們看到的都是只有“一層”的集合⊥痰桑現(xiàn)在我們再來看一下當集合的成員也是集合類的時候偷拔,復(fù)制的情況廓块。
- 淺復(fù)制
首先明確一點:集合類本身的深復(fù)制,并不代表其成員也進行了深復(fù)制买决。用一張?zhí)O果文檔的圖來表示:
左側(cè)是淺復(fù)制沛婴,右側(cè)是深復(fù)制。然而很多人都把左側(cè)的這種當成了集合的深復(fù)制督赤,這是需要注意的一個誤區(qū)嘁灯。
進行淺復(fù)制有很多方式,但這里著重說明一種方式:
NSArray *shallowCopyArray = [someArray copyWithZone:nil];
NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:NO];
注意這里躲舌,方法 initWithDictionary:copyItems:
第二個參數(shù)如果填NO丑婿,得到的僅僅是對最外層集合對象的深復(fù)制,而其內(nèi)部成員都只是接收到一個retain消息没卸。
- 單層深復(fù)制
如果方法initWithDictionary:copyItems:
第二個參數(shù)填YES羹奉,最外層集合對象被深復(fù)制,并且其內(nèi)部第一層成員(可能是非容器類對象例如String约计,也可能是容器類對象)都收到copy消息诀拭。因此,如果其第一層內(nèi)部成員是可變的煤蚌,那么該方法調(diào)用的結(jié)果是耕挨,第一層所有可變成員被深復(fù)制细卧,而所有第一層不可變成員(如果有的話)會被淺復(fù)制。
注意俗孝,如果接收到copy消息的成員沒有遵循NSCopying協(xié)議酒甸,則程序?qū)罎ⅰ?/em>
- 全層深復(fù)制
如果希望集合類本身及其所有層都被深復(fù)制,則可以對集合類先歸檔再解檔赋铝。當然,這么操作的前提是所有成員都遵循了NSCopying協(xié)議沽瘦。
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
- 各種復(fù)制方式的可變性
當我們對集合進行復(fù)制操作時革骨,集合類和其成員的可變性都會受到影響。
讓表層集合對象成為immutable對象析恋。其所有成員的可變性保持原樣良哲。
第二參數(shù)設(shè)置為NO,會讓表層集合對象的可變性和創(chuàng)建它的類型一致助隧。其所有成員的可變性保持原樣筑凫。
第二參數(shù)設(shè)置為YES,會讓表層集合對象的可變性和創(chuàng)建它的類型一致并村。第二層成員變?yōu)閕mmutable的巍实。其所有成員的可變性保持原樣。
下集預(yù)告
NSString *a = @"a";
NSString *b = [a copy];
NSString *c = [a mutableCopy];
NSLog(@"a地址:%d,b地址:%d,c地址:%d",a,b,c);
打印哩牍,得到:
可以看到棚潦,如果使用一個字符串常量給a賦值,則copy生成的是不可變對象膝昆,且是淺拷貝丸边。關(guān)于字符串的問題,我會另外開一篇文章來探討荚孵。