分類是開發(fā)中經(jīng)常需要使用的,但是短板就在于能夠給分類添加屬性撕氧,卻不能自動(dòng)生成屬性的setter和getter瘤缩,所以在運(yùn)行時(shí),會(huì)報(bào)錯(cuò)找不到setter和getter方法而直接崩潰伦泥。這時(shí)候剥啤,Runtime就可以解決這個(gè)短板。
廢話不多說(shuō)不脯,先上代碼:
我們先創(chuàng)建一個(gè)UIView的分類:UIView+Extension
//.h文件
#import <UIKit/UIKit.h>
@interface UIView (Extension)
@property (nonatomic,strong) NSString* value;
@end
//.m文件
#import "UIView+Extension.h"
#import <objc/runtime.h>
@implementation UIView (Extension)
- (void)setValue:(NSString *)value {
objc_setAssociatedObject(self, @selector(value), value, OBJC_ASSOCIATION_RETAIN);
}
- (NSString *)value {
return objc_getAssociatedObject(self, _cmd);//_cmd代表本方法的名稱
}
@end
簡(jiǎn)單吧府怯,接下來(lái)就是直接在需要使用的地方import
進(jìn)去即可,然后就可以當(dāng)做一個(gè)普通的屬性使用了防楷。
關(guān)于其原理牺丙,實(shí)際上就是利用了我們的屬性的getter
和setter
方法,在方法中用Runtime為對(duì)象動(dòng)態(tài)添加屬性复局,也就是添加一個(gè)地址和值的關(guān)聯(lián)赘被,通過(guò)objc_setAssociatedObject
進(jìn)行關(guān)聯(lián)設(shè)置肖揣,通過(guò)objc_getAssociatedObject
進(jìn)行取值的操作民假。
關(guān)于Associated Objects
,就以下三個(gè)相關(guān)方法
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
id objc_getAssociatedObject(id object, const void *key);
void objc_removeAssociatedObjects(id object);
① 其中龙优,void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
這個(gè)方法用于給對(duì)象添加關(guān)聯(lián)對(duì)象羊异,它有四個(gè)參數(shù):
id object
:需要添加關(guān)聯(lián)的源對(duì)象
const void *key
:關(guān)聯(lián)時(shí)的用來(lái)標(biāo)記是哪一個(gè)屬性的key(因?yàn)槟憧赡芤砑雍芏鄬傩裕?br>
id value
:關(guān)聯(lián)的對(duì)象
objc_AssociationPolicy policy
:關(guān)聯(lián)策略
值得一提的是key
參數(shù),常見(jiàn)的做法有以下幾種:
//利用靜態(tài)變量地址唯一不變的特性
1野舶、static void *theKey = &theKey;
2易迹、static NSString *theKey = @"theKey";
3、static char theKey;
但是我個(gè)人最喜歡的平道,還是上面的代碼中使用的方法,直接取@selector
一屋,用getter
方法名做key窘疮,省掉了一個(gè)變量名冀墨,夠優(yōu)(zhuang)雅(bi)闸衫。
② 第二個(gè)id objc_getAssociatedObject(id object, const void *key);
顯而易見(jiàn)是根據(jù)key
獲取值。
③ 最后一個(gè)void objc_removeAssociatedObjects(id object);
方法是移除關(guān)聯(lián)的诽嘉,很少用到蔚出,也不建議使用,因?yàn)檫@個(gè)函數(shù)會(huì)移除一個(gè)對(duì)象的所有關(guān)聯(lián)對(duì)象骄酗,將該對(duì)象恢復(fù)成“原始”狀態(tài)。這樣做就很有可能把別人添加的關(guān)聯(lián)對(duì)象也一并移除悦冀,這并不是我們所希望的。所以一般的做法是通過(guò)給 objc_setAssociatedObject
函數(shù)傳入 nil
來(lái)移除某個(gè)已有的關(guān)聯(lián)對(duì)象雏门。
關(guān)聯(lián)策略
objc_AssociationPolicy policy
是一個(gè)枚舉值,包括:
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
OBJC_ASSOCIATION_RETAIN = 01401,
OBJC_ASSOCIATION_COPY = 01403
};
簡(jiǎn)單的來(lái)說(shuō)茁影,就是你添加的屬性是用什么修飾的,就選擇對(duì)應(yīng)的策略募闲。
枚舉值 | 對(duì)應(yīng)屬性 | 說(shuō)明 |
---|---|---|
OBJC_ASSOCIATION_ASSIGN | @property (assign) or @property (unsafe_unretained) | 弱引用關(guān)聯(lián)對(duì)象 |
OBJC_ASSOCIATION_RETAIN_NONATOMIC | @property (strong, nonatomic) | 強(qiáng)引用關(guān)聯(lián)對(duì)象,且為非原子操作 |
OBJC_ASSOCIATION_COPY_NONATOMIC | @property (copy, nonatomic) | 復(fù)制關(guān)聯(lián)對(duì)象浩螺,且為非原子操作 |
OBJC_ASSOCIATION_RETAIN | @property (strong, atomic) | 強(qiáng)引用關(guān)聯(lián)對(duì)象靴患,且為原子操作 |
OBJC_ASSOCIATION_COPY | @property (copy, atomic) | 復(fù)制關(guān)聯(lián)對(duì)象要出,且為原子操作 |