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

前言

在開發(fā)中經(jīng)常需要給已有的類添加方法和屬性鸠删,但是Objective-C是不允許給已有類通過分類添加屬性的怯屉,因為類分類是不會自動生成成員變量的。但是附较,我們可以通過運行時機制就可以做到了吃粒。

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

API介紹

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

/** 
 * 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)

實際上早像,我們幾乎不會使用到objc_removeAssociatedObjects函數(shù)僻肖,這個函數(shù)的功能是移除指定的對象上所有的關(guān)聯(lián)。既然我們要添加關(guān)聯(lián)屬性卢鹦,幾乎不會存在需要手動取消關(guān)聯(lián)的場合臀脏。

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

對于設(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:唯一鍵谁榜,在獲取值時通過該鍵獲取,通常是使用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)時所指定的與哪個對象關(guān)聯(lián)的那個對象
  • key:唯一鍵,在設(shè)置關(guān)聯(lián)時所指定的鍵

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

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

/**
 * 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. */
};

我們說明一下各個值的作用:

  • OBJC_ASSOCIATION_ASSIGN:表示弱引用關(guān)聯(lián),通常是基本數(shù)據(jù)類型答渔,如int关带、float,非線程安全
  • OBJC_ASSOCIATION_RETAIN_NONATOMIC:表示強(strong)引用關(guān)聯(lián)對象,非線程安全
  • OBJC_ASSOCIATION_COPY_NONATOMIC:表示關(guān)聯(lián)對象copy宋雏,非線程安全
  • OBJC_ASSOCIATION_RETAIN:表示強(strong)引用關(guān)聯(lián)對象芜飘,是線程安全的
  • OBJC_ASSOCIATION_COPY:表示關(guān)聯(lián)對象copy,是線程安全的

擴展屬性

我們來寫一個例子磨总,擴展UIControl添加Block版本的TouchUpInside事件嗦明。

擴展頭文件聲明:

#import <UIKit/UIKit.h>

typedef void (^HYBTouchUpBlock)(id sender);

@interface UIControl (HYBBlock)

@property (nonatomic, copy) HYBTouchUpBlock hyb_touchUpBlock;

@end

擴展實現(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

使用起來很簡單吧!r窖唷娶牌!

小結(jié)

本文章是專門介紹通過runtime如何給已有類添加擴展屬性,如果文章中出現(xiàn)有疑問的地方馆纳,請在評論中評論诗良,筆者會在第一時間回復(fù)您的!

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末灵嫌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子葛作,更是在濱河造成了極大的恐慌寿羞,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赂蠢,死亡現(xiàn)場離奇詭異绪穆,居然都是意外死亡,警方通過查閱死者的電腦和手機虱岂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門玖院,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人第岖,你說我怎么就攤上這事难菌。” “怎么了蔑滓?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵郊酒,是天一觀的道長。 經(jīng)常有香客問我键袱,道長燎窘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任蹄咖,我火速辦了婚禮褐健,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘澜汤。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布圆雁。 她就那樣靜靜地躺著贼涩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪历涝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音烛缔,去河邊找鬼。 笑死轩拨,一個胖子當(dāng)著我的面吹牛践瓷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亡蓉,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼晕翠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了砍濒?” 一聲冷哼從身側(cè)響起淋肾,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爸邢,沒想到半個月后樊卓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡杠河,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年碌尔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片券敌。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡唾戚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出待诅,到底是詐尸還是另有隱情叹坦,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布卑雁,位于F島的核電站立由,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏序厉。R本人自食惡果不足惜锐膜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望弛房。 院中可真熱鬧道盏,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至种远,卻和暖如春涩澡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坠敷。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工妙同, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人膝迎。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓粥帚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親限次。 傳聞我的和親對象是個殘疾皇子芒涡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

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

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