iOS之 Category 屬性 的理解


在 Objective-C 中可以通過 Category 給一個現有的類添加屬性,但是卻不能添加實例變量

反正讀第一遍的時候我是有點暈的,可以添加“屬性”,然后又說“添加實例變量”,第一感覺就好像 有點自相矛盾了。那么我們談談:

  • 什么是實例變量?

    實例變量就是一種變量,可以存放數據的。在oc上,形式就如:        

@interface MyViewController :UIViewController
{
    UIButton *myButton;
}

@end
  • 什么是屬性?

  屬性是oc的一個新的機制,並且要求你必須聲明與之對應的實例變量,這是最早期的一種概念,隨着編譯器從GCC轉換為LLVM(low level virtual machine),從此不再需要為屬性聲明實例變量了,如果LLVM發現一個沒有匹配實例變量的屬性,它將自動創建一個以下划線開頭的實例變量。

  • Category可以給一個現有的類添加屬性

我建立了個 UIColor的hex分類  ,在UIColor+hex.h上我做了這么一件事:

然后做你會發現編譯器並不會報任何錯誤,build一下也不會有問題,當然這不能說這段代碼是可以運行的【crash】。仔細的話,你會發現在.m中是有警告的。

它說,屬性 hex的setHex和hex方法需要定義使用 @dynamic或者自己實現。  這里添加的屬性,不會自動生成實例變量,這里添加的屬性其實是添加的getter與setter方法。

這里,我們是不是可以理解上面的那句話了,其實就是等同於這句話

類別中只能添加方法,不能添加實例變量

 

首先,我們就用了@dynamic去做:

警告確實立馬消失,但是是不是可以運行了呢?夢想是美好的,結果依舊crash。

  • 那么這個@dynamic到底干了什么可以讓警告消除,當然你會不會發現這個@dynamic在哪里見過?對了在你用coredata的時候,你就會發現了【NSManagedObject自己探索去吧】。

       @dynamic 是相對於 @synthesize的,它們用樣用於修飾 @property,用於生成對應的的getter和setter方法。但是@ dynamic表示這個成員變量的getter和setter方法並不是直接由編譯器生成,而是手工生成或者運行時生成。

@dynamic just tells the compiler that the getter and setter methods are implemented not by the class itself but somewhere else (like the superclass or will be provided at runtime).

  那為什么會崩潰?哈哈,不要想當然了,因為你沒有在runtime中提供getter and setter methods。那當然會崩潰啦。

 

上面我們就基本上了解了在category添加屬性的一些問題。那么該如何解決這些問題,也是下面我想說的Associated Objects,let's  go!

首先我們帶着這么2個疑問:

  1. 關聯對象被存放到什么地方,是不是存放在被關聯對象本身的內存中?
  2. 關聯對象的生命周期怎么樣。什么時候被釋放,什么時候被移除?

 

上面是兩種方法的實現

  • objc_setAssociatedObject
  • objc_getAssociatedObject
  • objc_removeAssociatedObjects

其中第三個函數objc_removeAssociatedObjects 函數我們一般式用不上的,因為這個函數會移除一個對象的所有關聯對象,該將對象恢復為“

pristine state”。一般我我沒問你如果要移除一個關聯對象,我們會使用objc_setAssociatedObject 函數中傳入nil就可以移除。

 

  • 你會發現這兩個函數都有一個key,在關聯對象的時候我們使用了兩種形式,那么這個key的設置有什么要求么?

  key 值必須是一個對象級別的唯一常量

    從上面的兩種實現關聯對象的方法中,我們使用了兩種不同的key值

  1. static void *kAssociatedObjectKey = &kAssociatedObjectKey;
  2. selector ,使用 getter 方法的名稱作為 key 值。

  3. 其實還有一種 static char kAssociatedObjectKey;      objc_getAssociatedObject(self, &kAssociatedObjectKey);

  對比這三種方式,很多人都喜歡第二種

 

  • 關於這個 objc_AssociationPolicy(關聯策略)又是什么?

  

關聯策略

等價屬性

說明

OBJC_ASSOCIATION_ASSIGN

@property (assign) or @property (unsafe_unretained)

弱引用關聯對象

OBJC_ASSOCIATION_RETAIN_NONATOMIC

@property (strong, nonatomic)

強引用關聯對象,且為非原子操作

OBJC_ASSOCIATION_COPY_NONATOMIC

@property (copy, nonatomic)

復制關聯對象,且為非原子操作

OBJC_ASSOCIATION_RETAIN

@property (strong, atomic)

強引用關聯對象,且為原子操作

OBJC_ASSOCIATION_COPY

@property (copy, atomic)

復制關聯對象,且為原子操作

  上面這張表很清晰的告訴你這個關聯策略的作用。

  1. 關聯對象與被關聯對象本身的存儲並沒有直接的關系,它是存儲在單獨的哈希表中的;
  2. 關聯對象的五種關聯策略與屬性的限定符非常類似,在絕大多數情況下,我們都會使用 OBJC_ASSOCIATION_RETAIN_NONATOMIC 的關聯策略,這可以保證我們持有關聯對象;
  3. 關聯對象的釋放時機與移除時機並不總是一致,比如實驗中用關聯策略 OBJC_ASSOCIATION_ASSIGN 進行關聯的對象,很早就已經被釋放了,但是並沒有被移除,而再使用這個關聯對象時就會造成 Crash 。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM