iOS關于屬性關鍵字,你又知道多少?

LeviIEKD 7年前發布 | 11K 次閱讀 iOS開發 移動開發

分享是每個優秀的程序員所必備的品質

一、@property

  • @property 其實就是在編譯階段由編譯器自動幫我們生成ivar成員變量getter方法,setter方法。

使用“自動合成”( auto synthesis)這個過程由編譯器在編譯階段執行自動合成,所以編譯器里看不到這些“合成方法”(synthesized method)的源代碼。除了生成getter、setter方法之外,編譯器還要自動向類中添加成員變量(在屬性名前面加下劃線,以此作為實例變量的名字)反編譯相關的代碼大致生成:

OBJC_IVAR_$類名$屬性名稱        // 該屬性的“偏移量” (offset),這個偏移量是“硬編碼” (hardcode),表 示該變量距離存放對象的內存區域的起始地址有多遠

實際流程:

每次增加一個屬性,系統都會在 ivar_list 中添加一個成員變量的描述,在 method_list 中增加 setter 與 getter 方法的描述,在 prop_list 中增加一個屬性的描述,計算該屬性在對象中的偏移量,然后給出 setter 與 getter 方法對應的實現。

在 setter 方法中從偏移量的位置開始賦值,在 getter 方法中從偏移量開始取值,為了能夠讀取正確字節數,系統對象偏移量的指針類型進行了類型強轉。

二 、 readwrite,readonly,assign,retain,copy,nonatomic,atomic,strong,weak屬性的作用分別是什么。

關鍵字 注釋
readwrite 此標記說明屬性會被當成讀寫的,這也是默認屬性。
readonly 此標記說明屬性只可以讀,也就是不能設置,可以獲取。
assign 不會使引用計數加1,也就是直接賦值。
retain 會使引用計數加1。
copy 建立一個索引計數為1的對象,在賦值時使用傳入值的一份拷貝。
nonatomic 非原子性訪問,多線程并發訪問會提高性能。
atomic 原子性訪問。
strong 打開ARC時才會使用,相當于retain。
weak 打開ARC時才會使用,相當于assign,可以把對應的指針變量置為nil。

三 、什么情況使用 weak 關鍵字,相比 assign 有什么不同?

首先明白什么情況使用 weak 關鍵字?

在 ARC 中,在有可能出現循環引用的時候,往往要通過讓其中一端使用 weak 來解決,比如:

delegate 代理屬性,代理屬性也可使用
assign自身已經對它進行一次強引用,沒有必要再強引用一次,此時也會使用 weak
自定義IBOutlet 控件屬性一般也使用weak;當然,也可以使用 strong,但是建議使用 weak

weak 和 assign 的不同點:

  • weak 策略在屬性所指的對象遭到摧毀時,系統會將 weak 修飾的屬性對象的指針指向 nil,在 OC 給 nil 發消息是不會有什么問題的;如果使用 assign 策略在屬性所指的對象遭到摧毀時,屬性對象指針還指向原來的對象,由于對象已經被銷毀,這時候就產生了野指針,如果這時候在給此對象發送消息,很容造成程序奔潰assigin 可以用于修飾非 OC 對象,而 weak 必須用于 OC 對象。

四、使用 atomic 一定是線程安全的嗎?

  • 答案很明顯。不是,atomic 的本意是指屬性的存取方法是線程安全的,并不保證整個對象是線程安全的。

例如:

聲明一個 NSMutableArray 的原子屬性 stuff,此時 self.stuff 和 self.stuff =othersulf 都是線程安全的。但是,使用[self.stuff objectAtIndex:index]就不是線程安全的,需要用互斥鎖來保證線程安全性。

五、@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 的實例變量,那么還會自動合成新變量么?

先回答第二個問題:不會!!!不會!!!不會!!!

<p>@synthesize 合成成員變量的規則,有以下幾點:</p>
  • 如果指定了成員變量的名稱,會生成一個指定的名稱的成員變量如果這個成員已經存在了就不再生成了。
  • 如果指定@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) 在完全復制操作時,對于被復制對象的每一層都是對象復制。

非集合類對象的 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 協議。如果自定義的對象分為可變版本與不可變版本,那么就要同時實現 NSCopyiog 與NSMutableCopying 協議,不過一般沒什么必要,實現 NSCopying 協議就夠了

// 實現不可變版本拷貝

  • (id)copyWithZone:(NSZone *)zone; // 實現可變版本拷貝
  • (id)mutableCopyWithZone:(NSZone *)zone; // 重寫帶 copy 關鍵字的 setter
  • (void)setName:(NSString *)name { _name = [name copy]; }</code></pre>

     

    來自:http://www.jianshu.com/p/8b3cf2187255

     

 本文由用戶 LeviIEKD 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!