OC
中方法调用在运行时的过程
首先,在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现并执行。
如果没找到,在相应操作的对象中的方法列表中找调用的方法,如果找到,转向相应实现执行
如果没找到,去父类指针所指向的对象中执行1,2.
以此类推,如果一直到根类还没找到,转向拦截调用。
如果没有重写拦截调用的方法,程序报错。
拦截调用
在方法调用中说到了,如果没有找到方法就会转向拦截调用。
拦截调用就是,在找不到调用的方法程序崩溃之前,你有机会通过重写NSObject
的四个方法来处理。
+ (BOOL)resolveClassMethod:(SEL)sel;
+ (BOOL)resolveInstanceMethod:(SEL)sel;
//后两个方法需要转发到其他的类处理
- (id)forwardingTargetForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;
第一个方法是当你调用一个不存在的类方法的时候,会调用这个方法,默认返回
NO
,你可以加上自己的处理然后返回YES
。第二个方法和第一个方法相似,只不过处理的是实例方法。
第三个方法是将你调用的不存在的方法重定向到一个其他声明了这个方法的类,只需要你返回一个有这个方法的
target
。第四个方法是将你调用的不存在的方法打包成
NSInvocation
传给你。做完你自己的处理后,调用invokeWithTarget:
方法让某个target
触发这个方法。
具体流程如下:
具体事例可参考理解 Objective-C Runtime
动态添加方法
重写了拦截调用的方法并且返回了YES
,我们要怎么处理呢?
有一个办法是根据传进来的SEL
类型的selector
动态添加一个方法。
首先从外部隐式调用一个不存在的方法:
//隐式调用方法
[target performSelector:@selector(resolveAdd:) withObject:@"test"];
然后,在target
对象内部重写拦截调用的方法,动态添加方法。
1 | void runAddMethod(id self, SEL _cmd, NSString *string){ |
其中class_addMethod
的四个参数分别是:
Class cls
给哪个类添加方法,本例中是self
SEL name
添加的方法,本例中是重写的拦截调用传进来的selector
-IMP imp
方法的实现,C方法的方法实现可以直接获得。如果是OC方法,可以用
+ (IMP)instanceMethodForSelector:(SEL)aSelector
"v@:*"
方法的签名,代表有一个参数的方法
方法交换
方法交换,顾名思义,就是将两个方法的实现交换。例如,将A方法和B方法交换,调用A方法的时候,就会执行B方法中的代码,反之亦然。
话不多说,这是参考Mattt大神在NSHipster上的文章自己写的代码。
1 |
|
在一个自己定义的viewController中重写viewWillAppear
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSLog(@"viewWillAppear");
}