「翻譯」運行時之關聯對象

頭文件html

#import <objc/runtime.h>

Objective-C 開發者習慣於警戒運行時的東西,理由是運行時改變了運行在它上面代碼的實際結構。ios

另外一方面,<objc/runtime.h> 的功能就是爲應用或框架增長更強大的新特性,是其餘的方式沒法git

實現的。同時它也可能破壞原來代碼的邏輯結構,一切與之可能進行的交互,都將有可怕的反作用github

給咱們帶來極大的惶恐,所以,咱們稱之爲浮士德,也是NSHipster讀者常常被所要求的科目之一:緩存

關聯的對象關聯的對象或關聯的引用,他們本來是Objective-C的2.0運行時的新特性,在OS Xapp

雪豹中介紹(可在iOS 4的)的功能。運行時鍵值許對象爲任意值,這個條目是在框架

<objc/ runtime.h>聲明的如下三個C函數異步

  • objc_setAssociatedObject
  • objc_getAssociatedObject
  • objc_removeAssociatedObjects

爲何會這樣有用嗎?它容許開發人員在分類中自定義屬性,拓展的類,彌補Objective-C的這個缺陷ide

 
 
NSObject+AssociatedObject.h

@interface
NSObject (AssociatedObject) @property (nonatomic, strong) id associatedObject; @end
NSObject+AssociatedObject.m

@implementation NSObject (AssociatedObject)
@dynamic associatedObject;

- (void)setAssociatedObject:(id)object {
     objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id)associatedObject {
    return objc_getAssociatedObject(self, @selector(associatedObject));
}

人們一般的建議是使用靜態字符,或者更好的是指針。這基本上保證一個任意的值是固定的、惟一的,函數

並且僅限於getter和setter方法​​中使用

static char kAssociatedObjectKey;

objc_getAssociatedObject(self, &kAssociatedObjectKey);

然而一個更簡單的解決方案存在:只使用一個SEL

 

關聯對象的行爲

值能夠根據由枚舉類型objc_AssociationPolicy定義的行爲相關聯的物體上

 
Behavior @property Equivalent Description
OBJC_ASSOCIATION_ASSIGN @property (assign) or @property (unsafe_unretained) Specifies a weak reference to the associated object.
OBJC_ASSOCIATION_RETAIN_NONATOMIC @property (nonatomic, strong) Specifies a strong reference to the associated object, and that the association is not made atomically.
OBJC_ASSOCIATION_COPY_NONATOMIC @property (nonatomic, copy) Specifies that the associated object is copied, and that the association is not made atomically.
OBJC_ASSOCIATION_RETAIN @property (atomic, strong) Specifies a strong reference to the associated object, and that the association is made atomically.
OBJC_ASSOCIATION_COPY @property (atomic, copy) Specifies that the associated object is copied, and that the association is made atomically.
 
 
弱引用與OBJC_ASSOCIATION_ASSIGN是有區別的,弱引用和unsafe_unretained行爲相似,這
意味着應該謹慎地實現訪問弱關聯的對象。 根據在WWDC2011會話322(〜36:00)的Deallocation
Timeline 描述,相關聯對象的刪除遲於該對象的生命週期,在object_dispose(),它是由NSObject
的-dealloc調用。

移除值

有人可能控制不住地各類誘惑,在他們某些關聯的對象時調用objc_removeAssociatedObjects()。

可是,如文檔中描述的,你基本沒有將有機會親自調用它: 此函數的主要目的是能夠很容易將對象返回

「原始狀態」,你不該該使用這個函數從對象通常移除關聯,由於它也消除了其餘對象可能已添加到該

對象關聯。一般狀況下,你應該使用objc_setAssociatedObject 設置nil,以清除關聯

模式

  • 添加私有變量,以方便實現細節。當延伸的內置類的行爲時,記錄附加狀態多是必要的。這是能夠當作教科書的關聯對象的例子。例如,AFNetworking在UIImageView分類中使用關聯對象來存儲請求操做的對象,用於異步獲取一個遠程、特定的URL上的圖像。
  • 添加公共屬性來配置類的行爲。有時,用屬性可使分類更加靈活,比方法參數也更有意義。在這種狀況下,一個面向大衆的屬性是使用關聯的對象是能夠接受的。回到AFNetworking例子中,它的UIImageView分類的imageResponseSerializer,容許圖像視圖有選擇地應用過濾 器,另外一方面也能夠在設置和緩存到磁盤前更改遠程圖像的渲染。
  • 建立一個KVO的關聯觀察者。當在分類的實現中使用KVO時,一般推薦使用自定義的關聯對象能夠做爲一個觀察者,而不是觀察的對象自己。

反模式

  • 不須要值時存儲關聯的對象。一個常見的視圖模式是建立填充基於模型對象或複合值的字段和屬性的便捷方法。若是該值之後不須要回調,就不與該對象相關聯,這是能夠接受的,也是合理的。
  • 當 值能夠被推斷出來時存儲關聯的對象。例如,一我的也許會存儲一個自定義輔助視圖的包含的UITableViewCell的引用,用於實現代碼如 下:tableView:accessoryButtonTappedForRowWithIndexPath:,這時候能夠經過調用 cellForRowAtIndexPath: 恢復。
  • 在以下的狀況使用關聯的對象
    • 繼承比組合更合理時的子類
    • 添加交互事件響應的 "目標-動做"
    • 目標-動做不起做用時的 手勢識別
    • 行爲能夠委託給另外一個對象的代理。
    • 鬆耦合方式的跨系統通訊事件的通知、通知中心

相關聯的對象應被看做是不得已的方法,而不是尋找問題的解決方案(說真的,類自己真的不該該在工具鏈的頂端開始)。 如同任何聰明的把戲,駭客攻擊,或解決方法,通常都會積極尋求應用的場合,尤爲是瞭解以後,這是人的一種天然的傾向 。盡你所能地理解和欣賞時,這是正確的解決方案,保存本身被輕蔑地問:「爲何要以神的名義」,而後你決定去解決。

 

相關代碼:

https://github.com/skyming/BlockUI/tree/master/BlockUI

相關文章
相關標籤/搜索