返回
拒绝滥杀无辜!拦截unrecognized selector 拦截的正确方式
IOS
2024-02-24 12:54:37
unrecognized selector 拦截是一种常见的需求,它可以在对象没有实现某个方法时拦截并处理该方法调用。unrecognized selector 拦截有两种主要方式:动态方法解析和消息转发。
动态方法解析
动态方法解析是在编译时完成的。当编译器遇到一个对象没有实现的方法调用时,它会自动生成一个动态方法解析函数。该函数会在运行时被调用,以确定如何处理该方法调用。
动态方法解析有以下优点:
- 速度快,因为它是编译时完成的。
- 可以在编译时检测到方法不存在的错误。
- 可以通过重写动态方法解析函数来定制方法的处理方式。
动态方法解析也有以下缺点:
- 只能拦截在编译时已知的类的方法调用。
- 不能拦截在运行时动态创建的类的方法调用。
消息转发
消息转发是在运行时完成的。当对象收到一个它没有实现的方法调用时,它会将该方法调用转发给另一个对象。
消息转发有以下优点:
- 可以拦截任何对象的方法调用,无论该类是否在编译时已知。
- 可以拦截在运行时动态创建的类的方法调用。
消息转发也有以下缺点:
- 速度慢,因为它是在运行时完成的。
- 难以调试,因为方法调用的实际处理位置可能很难找到。
如何选择拦截方案
在选择 unrecognized selector 拦截方案时,需要考虑以下因素:
- 需要拦截的方法调用的类型。
- 拦截方案的速度要求。
- 拦截方案的调试难度。
如果需要拦截在编译时已知的类的方法调用,并且对速度要求不高,那么可以使用动态方法解析。如果需要拦截任何对象的方法调用,或者对速度要求很高,那么可以使用消息转发。
建议
建议使用消息转发来拦截 unrecognized selector。消息转发虽然速度较慢,但它可以拦截任何对象的方法调用,并且调试起来相对容易。
以下是一些使用消息转发来拦截 unrecognized selector 的示例代码:
- (id)forwardingTargetForSelector:(SEL)aSelector {
if ([self respondsToSelector:aSelector]) {
return self;
} else {
return nil;
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
if (!signature) {
signature = [NSMethodSignature signatureWithObjCTypes:"@@:"];
}
return signature;
}
- (id)forwardInvocation:(NSInvocation *)anInvocation {
SEL selector = [anInvocation selector];
if ([self respondsToSelector:selector]) {
[anInvocation invokeWithTarget:self];
} else {
[self doesNotRecognizeSelector:selector];
}
}
这只是使用消息转发来拦截 unrecognized selector 的一种方法。还有许多其他方法可以实现这一目标。开发者可以根据自己的具体需求来选择最合适的方法。