Runtime(也就是運(yùn)行時(shí))舶斧,它基本上是用C和匯編寫的,這個(gè)庫(kù)使得C語(yǔ)言有了面向?qū)ο蟮哪芰ΑK粤?xí)慣了面向?qū)ο缶幊痰男』飩兒孟駥?duì)于C的API一般都不太友好,但是又有很多C的API強(qiáng)大到別人問(wèn)你你不知道那你都抬不起頭媒役,Runtime就是其中之一。關(guān)于它的傳說(shuō)有很多宪迟,可以說(shuō)在有的人手里牛逼的不可一世酣衷。下面我們主要看一下runtime基本使用的方法:
1、獲取當(dāng)前類變量列表
不啰嗦直接上代碼:
獲取當(dāng)前類 的所以變量
unsigned int outCount;
Ivar *ivars = class_copyIvarList([PeopleModel class], &outCount);
SGTLog(@"\n\n\nPeopleModel類包含 變量數(shù)量:%u", outCount);
for (int i = 0; i < outCount; i++) {
Ivar ivar = ivars[i];
const char *ivarName = ivar_getName(ivar);
const char *ivarType = ivar_getTypeEncoding(ivar);
SGTLog(@"PeopleModel類包含 變量名為:%s 變量類型為:%s", ivarName, ivarType);
}
//由于ARC只適用于Foundation等框架次泽,對(duì)runtime 等并不適用穿仪,所以ivars需要free()手動(dòng)釋放。
free(ivars);
獲取當(dāng)前類 實(shí)例對(duì)象的所以變量
unsigned int count_p;
Ivar *ivars_p = class_copyIvarList([self.people class], &count_p);
SGTLog(@"\n\n\nself.people實(shí)例包含 變量數(shù)量:%u", count_p);
for (int i = 0; i < count_p; i++) {
Ivar ivar_p = ivars_p[i];
const char *ivarName_p = ivar_getName(ivar_p);
const char *ivarType_p = ivar_getTypeEncoding(ivar_p);
SGTLog(@"self.people實(shí)例包含 變量名為:%s 變量類型為:%s", ivarName_p, ivarType_p);
}
free(ivars_p);
打印結(jié)果
PeopleModel類包含 變量數(shù)量:7
2019-05-13 14:31:33.967546+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:78]
PeopleModel類包含 變量名為:_weight 變量類型為:f
2019-05-13 14:31:33.967704+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:78]
PeopleModel類包含 變量名為:_sex 變量類型為:B
2019-05-13 14:31:33.967838+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:78]
PeopleModel類包含 變量名為:_height 變量類型為:f
2019-05-13 14:31:33.967978+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:78]
PeopleModel類包含 變量名為:_age 變量類型為:q
2019-05-13 14:31:33.968102+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:78]
PeopleModel類包含 變量名為:_province 變量類型為:@"NSString"
2019-05-13 14:31:33.968225+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:78]
PeopleModel類包含 變量名為:_city 變量類型為:@"NSString"
2019-05-13 14:31:33.968349+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:78]
PeopleModel類包含 變量名為:_county 變量類型為:@"NSString"
2019-05-13 14:31:33.968561+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:85]
self.people實(shí)例包含 變量數(shù)量:7
2019-05-13 14:31:33.969885+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:91]
self.people實(shí)例包含 變量名為:_weight 變量類型為:f
2019-05-13 14:31:33.970044+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:91]
self.people實(shí)例包含 變量名為:_sex 變量類型為:B
2019-05-13 14:31:33.970163+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:91]
self.people實(shí)例包含 變量名為:_height 變量類型為:f
2019-05-13 14:31:33.970283+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:91]
self.people實(shí)例包含 變量名為:_age 變量類型為:q
2019-05-13 14:31:33.970397+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:91]
self.people實(shí)例包含 變量名為:_province 變量類型為:@"NSString"
2019-05-13 14:31:33.970513+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:91]
self.people實(shí)例包含 變量名為:_city 變量類型為:@"NSString"
2019-05-13 14:31:33.970630+0800 RuntimeDemo[19130:320593]
-[ViewController testIvar] [ViewController.m Line:91]
self.people實(shí)例包含 變量名為:_county 變量類型為:@"NSString"
2意荤、獲取當(dāng)前類屬性列表
代碼如下:
unsigned int outPropertyCount;
objc_property_t *propertys = class_copyPropertyList([PeopleModel class],&outPropertyCount);
SGTLog(@"\n\n\nPeopleModel類包含 屬性數(shù)量:%u", outPropertyCount);
for (int i = 0; i < outPropertyCount; i++) {
objc_property_t property = propertys[i];
const char *propertyName = property_getName(property);
const char *propertyAttributes = property_getAttributes(property);
SGTLog(@"nPeopleModel類包含 屬性名為:%s 變量屬性為:%s", propertyName, propertyAttributes);
}
free(propertys);
打印結(jié)果啊片,People類共有8個(gè)屬性
PeopleModel類包含 屬性數(shù)量:8
2019-05-13 14:52:17.738854+0800 RuntimeDemo[19435:328966]
-[ViewController testProperty] [ViewController.m Line:109]
nPeopleModel類包含 屬性名為:fatherName 變量屬性為:T@"NSString",C,D,N
2019-05-13 14:52:17.739009+0800 RuntimeDemo[19435:328966]
-[ViewController testProperty] [ViewController.m Line:109]
nPeopleModel類包含 屬性名為:motherName 變量屬性為:T@"NSString",C,D,N
2019-05-13 14:52:17.739128+0800 RuntimeDemo[19435:328966]
-[ViewController testProperty] [ViewController.m Line:109]
nPeopleModel類包含 屬性名為:age 變量屬性為:Tq,N,V_age
2019-05-13 14:52:17.739276+0800 RuntimeDemo[19435:328966]
-[ViewController testProperty] [ViewController.m Line:109]
nPeopleModel類包含 屬性名為:sex 變量屬性為:TB,N,V_sex
2019-05-13 14:52:17.739404+0800 RuntimeDemo[19435:328966]
-[ViewController testProperty] [ViewController.m Line:109]
nPeopleModel類包含 屬性名為:height 變量屬性為:Tf,N,V_height
2019-05-13 14:52:17.739541+0800 RuntimeDemo[19435:328966]
-[ViewController testProperty] [ViewController.m Line:109]
nPeopleModel類包含 屬性名為:province 變量屬性為:T@"NSString",C,N,V_province
2019-05-13 14:52:17.739697+0800 RuntimeDemo[19435:328966]
-[ViewController testProperty] [ViewController.m Line:109]
nPeopleModel類包含 屬性名為:city 變量屬性為:T@"NSString",C,N,V_city
2019-05-13 14:52:17.739849+0800 RuntimeDemo[19435:328966]
-[ViewController testProperty] [ViewController.m Line:109]
nPeopleModel類包含 屬性名為:county 變量屬性為:T@"NSString",C,N,V_county
2019-05-13 14:52:17.740080+0800 RuntimeDemo[19435:328966]
-[ViewController testProperty] [ViewController.m Line:116]
3、獲取當(dāng)前類方法列表
代碼如下:
unsigned int outMethodCount;
Method *methods = class_copyMethodList([PeopleModel class], &outMethodCount);
SGTLog(@"\n\n\nPeopleModel類包含 方法數(shù)量:%u", outMethodCount);
for (int i = 0; i < outMethodCount; i++) {
Method method = methods[i];
SEL method_name = method_getName(method);//方法名
const char * method_types = method_getTypeEncoding(method);//方法類型編碼
IMP method_imp = method_getImplementation(method);//方法實(shí)現(xiàn)
unsigned int ArgumentsNum = method_getNumberOfArguments(method);//參數(shù)個(gè)數(shù)
SGTLog(@"PeopleModel類包含 方法 名稱為:%@ 方法類型為:%s method_imp %p 參數(shù)個(gè)數(shù): %d ",NSStringFromSelector(method_name), method_types,&method_imp,ArgumentsNum);
}
free(methods);
打印結(jié)果顯示玖像,People共有方法22個(gè)包含屬性的setter getter 方法紫谷,也包含分類中的方法
PeopleModel類包含 方法數(shù)量:22
2019-05-13 17:30:45.841292+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:fatherName 方法類型為:@16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.841507+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:motherName 方法類型為:@16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.841651+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:isEat 方法類型為:B16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.841807+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:isEat 方法類型為:B16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.841945+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:isWork 方法類型為:B16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.842094+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:setFatherName: 方法類型為:v24@0:8@16 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 3
2019-05-13 17:30:45.842221+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:setMotherName: 方法類型為:v24@0:8@16 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 3
2019-05-13 17:30:45.853483+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:isHeight: 方法類型為:B24@0:8@16 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 3
2019-05-13 17:30:45.853635+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:sex 方法類型為:B16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.853767+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:setSex: 方法類型為:v20@0:8B16 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 3
2019-05-13 17:30:45.853892+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:province 方法類型為:@16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.854019+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:setProvince: 方法類型為:v24@0:8@16 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 3
2019-05-13 17:30:45.854145+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:county 方法類型為:@16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.854278+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:setCounty: 方法類型為:v24@0:8@16 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 3
2019-05-13 17:30:45.854402+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:.cxx_destruct 方法類型為:v16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.854522+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:dealloc 方法類型為:v16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.854748+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:height 方法類型為:f16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.855102+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:setHeight: 方法類型為:v20@0:8f16 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 3
2019-05-13 17:30:45.855471+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:setAge: 方法類型為:v24@0:8q16 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 3
2019-05-13 17:30:45.855768+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:age 方法類型為:q16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.856054+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:setCity: 方法類型為:v24@0:8@16 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 3
2019-05-13 17:30:45.856447+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:137]
PeopleModel類包含 方法 名稱為:city 方法類型為:@16@0:8 method_imp 0x7ffeea98c7f8 參數(shù)個(gè)數(shù): 2
2019-05-13 17:30:45.856783+0800 RuntimeDemo[25078:406610]
-[ViewController testMethod] [ViewController.m Line:146]
4、替換當(dāng)前類實(shí)例方法的實(shí)現(xiàn)(類方法同樣)
一樣捐寥,不啰嗦直接上代碼
/// 替換方法實(shí)現(xiàn)
SEL originalSelector = @selector(isEat);
SEL swizzledSelector = @selector(isWork);
// Method originalMethod = class_getInstanceMethod([PeopleModel class], originalSelector);
// Method swizzledMethod = class_getInstanceMethod([PeopleModel class], swizzledSelector);
//self.people 類型已被賦值為Model
Method originalMethod = class_getInstanceMethod([self.people class], originalSelector);
Method swizzledMethod = class_getInstanceMethod([self.people class], swizzledSelector);
// if (swizzledMethod == nil) {
// return;
// }
//1笤昨、交換兩個(gè)方法的實(shí)現(xiàn)
method_exchangeImplementations(originalMethod, swizzledMethod);
// IMP originalIMP = method_getImplementation(originalMethod);
// IMP swizzledIMP = method_getImplementation(swizzledMethod);
// //2、用swizzledMethod的實(shí)現(xiàn)取代originalMethod的實(shí)現(xiàn)
// class_replaceMethod([self.people class], originalSelector, swizzledIMP, method_getTypeEncoding(swizzledMethod));
//
// //3握恳、把swizzledVCMethod方法的實(shí)現(xiàn)賦值給originalMethod
// method_setImplementation(originalMethod,swizzledIMP);
//調(diào)用方法測(cè)試 //如果前邊調(diào)用了[self textClass]方法 self.people 類型已被賦值為Model 瞒窒,相當(dāng)于調(diào)用Model 實(shí)例的isEat方法,Model 未實(shí)現(xiàn)isEat方法乡洼,Model類作了消息截取崇裁,可以調(diào)用成功
[self.people isEat];
替換方法的實(shí)現(xiàn)有三種方法
1、交換兩個(gè)方法的實(shí)現(xiàn)
method_exchangeImplementations(originalMethod,swizzledMethod);
2束昵、用swizzledMethod的實(shí)現(xiàn)取代originalMethod的實(shí)現(xiàn)
class_replaceMethod([self.people class], originalSelector,method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
3拔稳、把swizzledVCMethod方法的實(shí)現(xiàn)賦值給originalMethod
method_setImplementation(originalMethod,method_getImplementation(swizzledMethod));
這三種方法都可以在調(diào)用originalMethod 的時(shí)候替換為swizzledMethod的實(shí)現(xiàn)
我們?cè)陧?xiàng)目中調(diào)用沒(méi)有實(shí)現(xiàn)的方法會(huì)崩潰,怎么避免呢妻怎?我們可以通過(guò)消息轉(zhuǎn)發(fā)來(lái)實(shí)現(xiàn),代碼如下泞歉,
并且重寫消息轉(zhuǎn)發(fā)的方法:
方法一:
//Model.m 文件中創(chuàng)建
-(void)noObjMethod{
NSLog(@"未實(shí)現(xiàn)這個(gè)實(shí)例方法");
}
+(void)noClassMethod{
NSLog(@"未實(shí)現(xiàn)這個(gè)類方法");
}
//并且重寫消息轉(zhuǎn)發(fā)的方法:
// 當(dāng)一個(gè)對(duì)象調(diào)用未實(shí)現(xiàn)的方法逼侦,會(huì)調(diào)用這個(gè)方法處理,并且會(huì)把對(duì)應(yīng)的方法列表傳過(guò)來(lái).
//注意:實(shí)例方法是存在于當(dāng)前對(duì)象對(duì)應(yīng)的類的方法列表中
+(BOOL)resolveInstanceMethod:(SEL)sel{
SEL aSel = NSSelectorFromString(@"noObjMethod");
Method aMethod = class_getInstanceMethod(self, aSel);
BOOL addMethod = class_addMethod(self, sel, method_getImplementation(aMethod), "v@:");
return addMethod;
}
// 當(dāng)一個(gè)類調(diào)用未實(shí)現(xiàn)的方法,會(huì)調(diào)用這個(gè)方法處理,并且會(huì)把對(duì)應(yīng)的方法列表傳過(guò)來(lái).
//注意:類方法是存在于類的元類的方法列表中
+(BOOL)resolveClassMethod:(SEL)sel{
SEL aSel = NSSelectorFromString(@"noClassMethod");
Method aMethod = class_getClassMethod(self, aSel);
BOOL addMethod = class_addMethod(object_getClass(self), sel, method_getImplementation(aMethod), "v@:");
return addMethod;
}
打印結(jié)果
2019-05-13 18:31:46.605919+0800 RuntimeDemo[28185:448815] 未實(shí)現(xiàn)這個(gè)實(shí)例方法
方法二:
//消息轉(zhuǎn)發(fā)
-(id)forwardingTargetForSelector:(SEL)aSelector{
//獲取people類
Class peopleClass = NSClassFromString(@"PeopleModel");
if (class_respondsToSelector(peopleClass, aSelector)) {
return [[peopleClass alloc]init];
}
return self;
}
打印結(jié)果
2019-05-13 18:35:25.711990+0800 RuntimeDemo[28222:449877]
-[PeopleModel(Family) isEat] [PeopleModel+Family.m Line:22]
(null) 沒(méi)有吃飯
方法三:
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if ([NSStringFromSelector(aSelector) isEqualToString:@"isEat"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
-(void)forwardInvocation:(NSInvocation *)anInvocation{
[anInvocation invokeWithTarget:[[NSClassFromString(@"PeopleModel") alloc] init]];
}
打印結(jié)果
2019-05-13 18:40:26.972046+0800 RuntimeDemo[28102:446152]
-[PeopleModel(Family) isEat] [PeopleModel+Family.m Line:22]
(null) 沒(méi)有吃飯
以上三種方法都可以實(shí)現(xiàn)消息轉(zhuǎn)發(fā)腰耙,在調(diào)用isEat時(shí)進(jìn)行處理榛丢,不會(huì)引起崩潰。
Runtime使用實(shí)例就先到這里了挺庞。
測(cè)試Demo地址直通車