/**
總結(jié):
在一個函數(shù)找不到時,OC提供了三種方式去補救:
1畦浓、調(diào)用resolveInstanceMethod給個機會讓類添加動態(tài)添加方法去實現(xiàn)這個函數(shù)
2、調(diào)用forwardingTargetForSelector讓別的對象去執(zhí)行這個函數(shù)
3、調(diào)用forwardInvocation(函數(shù)執(zhí)行器)靈活的將目標(biāo)函數(shù)以其他形式執(zhí)行蹦漠。用methodSignatureForSelector先偷換方法的簽名
如果都不中部凑,調(diào)用doesNotRecognizeSelector拋出異常露乏。
*/
#import"ViewController.h"
#import"Person.h"
#import"NSObject+Runtime.h"
@interfaceViewController()
@property(nonatomic,strong)Person*person;
@end
@implementationViewController
- (void)viewDidLoad {
[superviewDidLoad];
_person= [Personalloc];
[_personperformSelector:@selector(shaleba)];
}
@end
#import"Person.h"
#import
@implementationPerson
#pragma mark - crush最先調(diào)用,可以在這里用運行時交換方法
+(BOOL)resolveInstanceMethod:(SEL)sel{
if(sel ==@selector(shaleba)) {
class_addMethod([selfclass],sel,class_getMethodImplementation(self,@selector(startEngine)),"@@:");
returnNO;
}
return[superresolveInstanceMethod:sel];
}
//上面??替換的方法
- (void)startEngine {
NSLog(@"我執(zhí)行后就不會再崩潰了");
}
#pragma mark - crush第二調(diào)用,可以在這里直接指定一個對象去調(diào)用
-(id)forwardingTargetForSelector:(SEL)aSelector{
self.stu= [studentnew];
returnself.stu;
}
#pragma mark - crush第3接鍋俠之一這個是和下面方法一起使用的,可以在這里直接指定一個對象去調(diào)用
-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{
self.stu= [studentnew];
NSMethodSignature*signature =nil;
//如果自己變身的類有改方法,則偷取出方法的簽名
if([self.stumethodSignatureForSelector:aSelector]) {
//OC所有的底層方法至少有兩個參數(shù)第一個參數(shù)方法的對象self第二個參數(shù):方法的自身我們?nèi)斯な謱懙姆椒▍?shù)是從第三個開始
signature = [self.stumethodSignatureForSelector:aSelector];
}
else{
signature = [supermethodSignatureForSelector:aSelector];
}
returnsignature;
}
#pragma mark - crush第3接鍋俠之一這個是和下面方法一起使用的,可以在這里直接指定一個對象去調(diào)用
//2.再檢查方法的實現(xiàn)(調(diào)用方法)
- (void)forwardInvocation:(NSInvocation*)invocation{
//設(shè)置方法的執(zhí)行者為自己copy的哪一個類,必須設(shè)置不然不會調(diào)用此方法
[invocationsetTarget:self.stu];
//動態(tài)攔截參數(shù),修改參數(shù)
if([self.stuisKindOfClass:NSClassFromString(@"Teacher")]) {
//argument:參數(shù)的地址index:參數(shù)的下標(biāo)
NSString*s =@"呵呵,被改了";
[invocationsetArgument:&satIndex:2];
}
//讓自己的替身類去調(diào)用方法
[invocationinvoke];
}
@end