前言
在開發(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)一下吧!