本文搬運(yùn)自黑馬社區(qū),原文小飛機(jī)直達(dá)
前文說道:關(guān)于屬性的創(chuàng)建以及部分關(guān)鍵字的解釋與區(qū)別,進(jìn)行了一定程度上的解釋。
具體可以查看:Objective-C屬性關(guān)鍵字淺析(上)
本文會(huì)繼續(xù)闡述一些跟屬性關(guān)鍵字有關(guān)的一些技術(shù)點(diǎn)。
一、@synthesize 和 @dynamic 分別有什么作用?
@property 有兩個(gè)對(duì)應(yīng)的詞,一個(gè)是@synthesize,一個(gè)是@dynamic。
如果@synthesize 和@dynamic 都沒寫,那么默認(rèn)的就是
@syntheszie var = _var;
@synthesize 的語義是如果你沒有手動(dòng)實(shí)現(xiàn) setter 方法和 getter 方法,那么編譯器會(huì)自動(dòng)為你加上這兩個(gè)方法。
@dynamic 告訴編譯器:屬性的 setter 與 getter 方法由用戶自己實(shí)現(xiàn),不自動(dòng)生成。(當(dāng)然對(duì)于 readonly 的屬性只需提供 getter 即可)
假如一個(gè)屬性被聲明為
@dynamic var;
然后你沒有提供@setter 方法和@getter 方法,編譯的時(shí)候沒問題,但是當(dāng)程序運(yùn)行到 instance.var = someVar,由于缺 setter方法會(huì)導(dǎo)致程序崩潰;
或者當(dāng)運(yùn)行到 someVar = instance.var 時(shí),由于缺 getter 方法同樣會(huì)導(dǎo)致崩潰。
編譯時(shí)沒問題,運(yùn)行時(shí)才執(zhí)行相應(yīng)的方法,這就是所謂的動(dòng)態(tài)綁定
二、ARC 下,不顯式指定任何屬性關(guān)鍵字時(shí),默認(rèn)的關(guān)鍵字都有哪些?
基本數(shù)據(jù):atomic,readwrite,assign
普通的 OC 對(duì)象:atomic,readwrite,strong
三、@synthesize 合成實(shí)例變量的規(guī)則是什么?假如 property 名為 foo,存在一個(gè)名為_foo 的實(shí)例變量,那么還會(huì)自動(dòng)合成新變量么?
先回答第二個(gè)問題:不會(huì)!!!不會(huì)!!!不會(huì)!!!
@synthesize 合成成員變量的規(guī)則,有以下幾點(diǎn):
如果指定了成員變量的名稱,會(huì)生成一個(gè)指定的名稱的成員變量如果這個(gè)成員已經(jīng)存在了就不再生成了。
如果指定@synthesize foo;就會(huì)生成一個(gè)名稱為 foo 的成員變量,也就是說:會(huì)自動(dòng)生成一個(gè)屬性同名的成員變量。
@interface XMGPerson:NSObject
@property (nonatomic, assign) int age;
@end
@implementation XMGPerson
// 不加這語句默認(rèn)生成的成員變量名為_age
// 如果加上這一句就會(huì)生成一個(gè)跟屬性名同名的成員變量
如果是 @synthesize foo = _foo; 就不會(huì)生成成員變量了
四、在有了自動(dòng)合成屬性實(shí)例變量之后,@synthesize 還有哪些使用場(chǎng)景?
首先的搞清楚什么情況下不會(huì) autosynthesis(自動(dòng)合成):
- 同時(shí)重寫了setter和getter時(shí)
- 重寫了只讀屬性的getter時(shí)
- 使用了@dynamic時(shí)
在 @protocol 中定義的所有屬性在 category 中定義的所有屬性重載的屬性,當(dāng)你在子類中重載了父類中的屬性,必須使用@synthesize 來手動(dòng)合成ivar。
應(yīng)用場(chǎng)景:
當(dāng)你同時(shí)重寫了 setter 和 getter 時(shí),系統(tǒng)就不會(huì)生成 ivar。這時(shí)候有兩種選擇手動(dòng)創(chuàng)建ivar
- 使用@synthesize foo = _foo
- 關(guān)聯(lián)@property與ivar可以用來修改成員變量名,一般不建議這么做,建議使用系統(tǒng)自動(dòng)生成的成員變量
五、 怎么用copy關(guān)鍵字?
NSString、NSArray、NSDictionary等等經(jīng)常使用copy關(guān)鍵字,是因?yàn)樗麄冇袑?duì)應(yīng)的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary。
為確保對(duì)象中的屬性值不會(huì)無意間變動(dòng),應(yīng)該在設(shè)置新屬性知識(shí)拷貝一份,保護(hù)其封裝性block,也經(jīng)常使用copy,關(guān)鍵字block。
使用 copy 是從 MRC 遺留下來的“傳統(tǒng)”,在 MRC 中,方法內(nèi)部的 block 是在棧區(qū)的,使用 copy 可以把它放到堆區(qū).
在 ARC 中寫不寫都行:對(duì)于 block 使用 copy 還是 strong 效果是一樣的,但是建議寫上 copy,因?yàn)檫@樣顯示告知調(diào)用者“編譯器會(huì)自動(dòng)對(duì) block 進(jìn)行了 copy 操作。"
六、用@property 聲明的 NSString(或 NSArray,NSDictionary)經(jīng)常使用 copy 關(guān)鍵字,為什么?如果改用 strong 關(guān)鍵字,可能造成什么問題?
因?yàn)楦割愔羔樋梢灾赶蜃宇悓?duì)象,使用 copy 的目的是為了讓本對(duì)象的屬性不受外界影響,使用 copy 無論給我傳入是一個(gè)可變對(duì)象還是不可對(duì)象,我本身持有的就是一個(gè)不可變的副本.
如果我們使用是 strong,那么這個(gè)屬性就有可能指向一個(gè)可變對(duì)象,如果這個(gè)可變對(duì)象在外部被修改了,那么會(huì)影響該屬性.
| 屬性 | 內(nèi)容 |
|---|---|
| 淺復(fù)制(shallow copy) | 在淺復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象的每一層都是指針復(fù)制。 |
| 深復(fù)制(one-level-deep copy) | 在深復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象,至少有一層是深復(fù)制。 |
| 完全復(fù)制(real-deep copy) | 在完全復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象的每一層都是對(duì)象復(fù)制。 |
復(fù)制詳解:
| 屬性 | 內(nèi)容 |
|---|---|
| 淺復(fù)制(shallow copy) | 在淺復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象的每一層都是指針復(fù)制。 |
| 深復(fù)制(one-level-deep copy) | 在深復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象,至少有一層是深復(fù)制。 |
| 完全復(fù)制(real-deep copy) | 在完全復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象的每一層都是對(duì)象復(fù)制。 |
非集合類對(duì)象的 copy 與 mutableCopy
[不可變對(duì)象 copy] // 淺復(fù)制
[不可變對(duì)象 mutableCopy] //深復(fù)制
[可變對(duì)象 copy] //深復(fù)制
[可變對(duì)象 mutableCopy] //深復(fù)制
類對(duì)象的 copy 與 mutableCopy
[不可變對(duì)象 copy] // 淺復(fù)制
[不可變對(duì)象 mutableCopy] //單層深復(fù)制
[可變對(duì)象 copy] //單層深復(fù)制
[可變對(duì)象 mutableCopy] //單層深復(fù)
這里需要注意的時(shí)集合對(duì)象的內(nèi)容復(fù)制僅限于對(duì)象本身,對(duì)象元素仍然是指針復(fù)制。
七、 這個(gè)寫法會(huì)出什么問題?:@property(copy)NSMutableArray *array;
因?yàn)?copy 策略拷貝出來的是一個(gè)不可變對(duì)象,然而卻把它當(dāng)成可變對(duì)象使用,很容易造成程序奔潰這里還有一個(gè)問題,該屬性使用了同步鎖,會(huì)在創(chuàng)建時(shí)生成一些額外的代碼用于幫助編寫多線程程序,這會(huì)帶來性能問題,通過聲明 nonatomic 可以節(jié)省這些雖然
很小但是不必要額外開銷,在 iOS 開發(fā)中應(yīng)該使用 nonatomic 替代 atomic.
八、如何讓自定義類可以用 copy 修飾符?如何重寫帶 copy 關(guān)鍵字的 setter?
若想令自己所寫的對(duì)象具有拷貝功能,則需實(shí)現(xiàn)NSCopying協(xié)議。如果自定義的對(duì)象分為可變版本與不可變版本,那么就要同時(shí)實(shí)現(xiàn)NSCopying和NSMutableCopying協(xié)議,不過一般沒什么必要,實(shí)現(xiàn)NSCopying協(xié)議就夠了
// 實(shí)現(xiàn)不可變版本拷貝
- (id)copyWithZone:(NSZone *)zone; // 實(shí)現(xiàn)可變版本拷貝
- (id)mutableCopyWithZone:(NSZone *)zone;
// 重寫帶 copy 關(guān)鍵字的 setter
- (void)setName:(NSString *)name {
_name = [name copy];
}