動(dòng)態(tài)添加方法
動(dòng)態(tài)添加方法,就是使用performSelector來添加方法,也就相當(dāng)于懶加載機(jī)制。
如果一個(gè)類的方法很多,加載類到內(nèi)存的時(shí)候耗費(fèi)資源,需要給每個(gè)方法生成映射表,可以使用動(dòng)態(tài)給某個(gè)類,添加方法解決。
首先創(chuàng)建一個(gè)對(duì)象Child,引入runtime頭文件,#import <objc/message.h>
。實(shí)現(xiàn)動(dòng)態(tài)添加方法,首先要實(shí)現(xiàn)這個(gè)方法:resolveInstanceMethod
。
resolveInstanceMethod
調(diào)用:當(dāng)一個(gè)方法沒有實(shí)現(xiàn),但是又調(diào)用了這個(gè),就會(huì)調(diào)用。
resolveInstanceMethod
作用:知道哪些方法沒有實(shí)現(xiàn),從而動(dòng)態(tài)添加方法。
class_addMethod(Class cls, SEL name, IMP imp, const char *types)
:
動(dòng)態(tài)添加方法時(shí)調(diào)用:
1.class:給哪個(gè)類添加方法
2.SEL:方法編號(hào)
3.IMP:方法的實(shí)現(xiàn),函數(shù)入口(指針)
4.types:方法類型,蘋果官方文檔可以查詢。
//定義函數(shù)
/*
一個(gè)方法默認(rèn)都有兩個(gè)參數(shù):self,_cmd(隱式參數(shù))
self:方法調(diào)用者
_cmd:調(diào)用方法的編號(hào)
*/
void home(id self, SEL _cmd, id number)
{
NSLog(@"調(diào)用了child %@ %@ %@",self,NSStringFromSelector(_cmd),number);
}
//sel:沒有實(shí)現(xiàn)方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
//動(dòng)態(tài)添加child方法
if (sel == @selector(child:)) {
class_addMethod(self, sel, (IMP)home, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
在控制器中,引入頭文件#import "Child.h"
//動(dòng)態(tài)添加
Child * c = [[Child alloc] init];
[c performSelector:@selector(child:) withObject:@111];
運(yùn)行結(jié)果:
2017-01-18 14:01:34.178 [74402:6542779] 調(diào)用了child <Child: 0x61800000a610> child: 111
動(dòng)態(tài)添加屬性
給一個(gè)類聲明屬性,其實(shí)本質(zhì)就是給這個(gè)類添加關(guān)聯(lián),并不是直接把這個(gè)值的內(nèi)存空間添加到類存空間,也就是對(duì)象本身的屬性可以關(guān)聯(lián)到另外一個(gè)內(nèi)存中。
例如,我給NSObject寫一個(gè)分類,分類中,定義一個(gè)屬性name:@property (nonatomic, strong) NSString * name;
//這樣寫法,對(duì)象在,屬性就會(huì)一直在
NSObject * oc = [[NSObject alloc] init];
oc.name = @"123";
現(xiàn)在,我通過runtime動(dòng)態(tài)添加屬性,在需要用到的時(shí)候,再添加。引入runtime頭文件:#import <objc/message.h>
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
動(dòng)態(tài)添加屬性,給某個(gè)對(duì)象產(chǎn)生關(guān)聯(lián),添加屬性:
1.object:給哪個(gè)對(duì)象添加屬性
2.key:屬性名,根據(jù)key去獲取關(guān)聯(lián)的對(duì)象,void * == id
3.value:關(guān)聯(lián)的值
4.policy:策略
//添加屬性,跟對(duì)象有關(guān)
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, @"name");
}
在控制器中,代碼如下:
NSObject * objc = [[NSObject alloc] init];
objc.name = @"123";
NSLog(@"%@",objc.name);
運(yùn)行結(jié)果:
2017-01-18 15:20:58.370 [77263:6593950] 123
總結(jié):其實(shí),自xcode 5之后,蘋果就不建議使用底層方法,之前沒接觸runtime的時(shí)候,一直覺得很神秘,通過學(xué)習(xí)了解,明白,使用runtime的方法,可以讓我們更好地了解OC的運(yùn)行機(jī)制,而且在某些開發(fā)場(chǎng)景,使用runtime能夠提高我們的開發(fā)效率。