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