runtime關(guān)聯(lián)屬性

前言

在開發(fā)中經(jīng)常需要給已有的類添加方法和屬性,但是Objective-C是不允許給已有類通過分類添加屬性的,因?yàn)轭惙诸愂遣粫?huì)自動(dòng)生成成員變量的。但是,我們可以通過運(yùn)行時(shí)機(jī)制就可以做到了。

本篇文章適合新手閱讀,手把手教你如何在項(xiàng)目中使用關(guān)聯(lián)屬性!

API介紹

我們先看看Runtime提供的關(guān)聯(lián)API,只有這三個(gè)API,使用也是非常簡(jiǎn)單的:

/** 
 * Sets an associated value for a given object using a given key and association policy.
 * 
 * @param object The source object for the association.
 * @param key The key for the association.
 * @param value The value to associate with the key key for object. Pass nil to clear an existing association.
 * @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
 * 
 * @see objc_setAssociatedObject
 * @see objc_removeAssociatedObjects
 */
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

/** 
 * Returns the value associated with a given object for a given key.
 * 
 * @param object The source object for the association.
 * @param key The key for the association.
 * 
 * @return The value associated with the key \e key for \e object.
 * 
 * @see objc_setAssociatedObject
 */
id objc_getAssociatedObject(id object, const void *key)

/** 
 * Removes all associations for a given object.
 * 
 * @param object An object that maintains associated objects.
 * 
 * @note The main purpose of this function is to make it easy to return an object 
 *  to a "pristine state”. You should not use this function for general removal of
 *  associations from objects, since it also removes associations that other clients
 *  may have added to the object. Typically you should use \c objc_setAssociatedObject 
 *  with a nil value to clear an association.
 * 
 * @see objc_setAssociatedObject
 * @see objc_getAssociatedObject
 */
void objc_removeAssociatedObjects(id object)

實(shí)際上,我們幾乎不會(huì)使用到objc_removeAssociatedObjects函數(shù),這個(gè)函數(shù)的功能是移除指定的對(duì)象上所有的關(guān)聯(lián)。既然我們要添加關(guān)聯(lián)屬性,幾乎不會(huì)存在需要手動(dòng)取消關(guān)聯(lián)的場(chǎng)合。

設(shè)置關(guān)聯(lián)值(Setter)

對(duì)于設(shè)置關(guān)聯(lián),我們需要使用下面的API關(guān)聯(lián)起來:

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

參數(shù)說明:

  • object:與誰關(guān)聯(lián),通常是傳self
  • key:唯一鍵,在獲取值時(shí)通過該鍵獲取,通常是使用static const void *來聲明
  • value:關(guān)聯(lián)所設(shè)置的值
  • policy:內(nèi)存管理策略,比如使用copy

獲取關(guān)聯(lián)值(Getter)

如果我們要獲取所關(guān)聯(lián)的值,需要通過key來獲取,調(diào)用如下函數(shù):

id objc_getAssociatedObject(id object, const void *key)

參數(shù)說明:

  • object:與誰關(guān)聯(lián),通常是傳self,在設(shè)置關(guān)聯(lián)時(shí)所指定的與哪個(gè)對(duì)象關(guān)聯(lián)的那個(gè)對(duì)象
  • key:唯一鍵,在設(shè)置關(guān)聯(lián)時(shí)所指定的鍵

關(guān)聯(lián)策略

我們先看看設(shè)置關(guān)聯(lián)時(shí)所指定的policy,它是一個(gè)枚舉類型,看官方說明:

/**
 * Policies related to associative references.
 * These are options to objc_setAssociatedObject()
 */
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. 
                                            *   The association is not made atomically. */
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. 
                                            *   The association is not made atomically. */
    OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.
                                            *   The association is made atomically. */
    OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.
                                            *   The association is made atomically. */
};

我們說明一下各個(gè)值的作用:

  • OBJC_ASSOCIATION_ASSIGN:表示弱引用關(guān)聯(lián),通常是基本數(shù)據(jù)類型,如intfloat,非線程安全
  • OBJC_ASSOCIATION_RETAIN_NONATOMIC:表示強(qiáng)(strong)引用關(guān)聯(lián)對(duì)象,非線程安全
  • OBJC_ASSOCIATION_COPY_NONATOMIC:表示關(guān)聯(lián)對(duì)象copy,非線程安全
  • OBJC_ASSOCIATION_RETAIN:表示強(qiáng)(strong)引用關(guān)聯(lián)對(duì)象,是線程安全的
  • OBJC_ASSOCIATION_COPY:表示關(guān)聯(lián)對(duì)象copy,是線程安全的

擴(kuò)展屬性

我們來寫一個(gè)例子,擴(kuò)展UIControl添加Block版本的TouchUpInside事件。

擴(kuò)展頭文件聲明:

#import <UIKit/UIKit.h>

typedef void (^HYBTouchUpBlock)(id sender);

@interface UIControl (HYBBlock)

@property (nonatomic, copy) HYBTouchUpBlock hyb_touchUpBlock;

@end

擴(kuò)展實(shí)現(xiàn)文件:

#import "UIControl+HYBBlock.h"
#import <objc/runtime.h>

static const void *sHYBUIControlTouchUpEventBlockKey = "sHYBUIControlTouchUpEventBlockKey";

@implementation UIControl (HYBBlock)

- (void)setHyb_touchUpBlock:(HYBTouchUpBlock)hyb_touchUpBlock {
  objc_setAssociatedObject(self,
                           sHYBUIControlTouchUpEventBlockKey,
                           hyb_touchUpBlock,
                           OBJC_ASSOCIATION_COPY);
  
  [self removeTarget:self
              action:@selector(hybOnTouchUp:)
    forControlEvents:UIControlEventTouchUpInside];
  
  if (hyb_touchUpBlock) {
    [self addTarget:self
             action:@selector(hybOnTouchUp:)
   forControlEvents:UIControlEventTouchUpInside];
  }
}

- (HYBTouchUpBlock)hyb_touchUpBlock {
  return objc_getAssociatedObject(self, sHYBUIControlTouchUpEventBlockKey);
}

- (void)hybOnTouchUp:(UIButton *)sender {
  HYBTouchUpBlock touchUp = self.hyb_touchUpBlock;
  
  if (touchUp) {
    touchUp(sender);
  }
}

@end

使用起來很簡(jiǎn)單吧!!!

小結(jié)

本文章是專門介紹通過runtime如何給已有類添加擴(kuò)展屬性,如果文章中出現(xiàn)有疑問的地方,請(qǐng)?jiān)谠u(píng)論中評(píng)論,筆者會(huì)在第一時(shí)間回復(fù)您的!

本篇文章中所提到的只是最常見的添加關(guān)聯(lián)屬性的方式之一,對(duì)于生成只讀的關(guān)聯(lián)屬性也是很常用的,自行實(shí)現(xiàn)一下吧!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 我們知道蘋果不允許我們自己給已經(jīng)存在的類通過分類添加方法的,但是有時(shí)候我們確實(shí)需要給某個(gè)類從而分類添加屬性,那么我...
    啊啊啊啊鋒閱讀 597評(píng)論 0 1
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,775評(píng)論 0 9
  • 1/12 2016周二晴轉(zhuǎn)陰雨期末復(fù)習(xí) 世界真的好兇殘 一整天都在復(fù)習(xí),從早到晚從早到晚,我看著太陽升起,然后又天...
    抓星星的小超閱讀 276評(píng)論 0 0
  • 還在努力糾結(jié)離婚簽字,還在傷心,還在思考,只會(huì)自己傷害自己。我問心無愧就行了。至于其他,只能聽天由命了。婚姻不是一...
    longlong8612009閱讀 125評(píng)論 0 0
  • 真正的講究,是做給自己看。 一個(gè)外形靚麗的女孩子,每天會(huì)把自己打扮漂亮出門去,穿最靚的衫,從眼睫毛到頭發(fā)絲,都美得...
    靈動(dòng)衣櫥管理閱讀 363評(píng)論 0 0