iOS 开发消息转发

261 阅读2分钟

开发中常见的错误

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController function]: unrecognized selector sent to instance 0x7fdd10d17e00'

这代表function 方法没有实现,常见于.h 声明了方法,但是.m没有实现,或者

[self performSelector:NSSelectorFromString(@"function")];

这种利用字符串生成方法的代码,

unrecognized selector sent to instance 0x7fdd10d17e00'原因是因为methodSignatureForSelector这个方法中,由于没有找到run对应的实现方法,所以返回了一个空的方法签名,最终导致程序报错崩溃 这些代码Xcode都不会抛出错误,OC会提供3次机会来挽救

方法一: 动态解析

声明替补方法

void function(id sf,SEL cd){
    
    NSLog(@"%@",sf);
    
    NSLog(@"%@",NSStringFromSelector(cd));
}

进行动态方法解析 利用运行时给对象添加方法

+(BOOL)resolveInstanceMethod:(SEL)sel 
{
    if (sel == @selector(function)) {
        class_addMethod(self, sel, (IMP)function, "v@:");
    }
    return [super resolveInstanceMethod:sel];
}

这样方法的执行被转发到替代方法中

方法二: 快速转发 再本实例找不到方法的实现,可以将消息转发到实现该方法的对象

实现方法的实例

@implementation Function
-(void)function
{
    NSLog(@"do function");
}
@end

实现快速消息转发 该方法的返回值就是执行未找到方法的对象

-(id)forwardingTargetForSelector:(SEL)aSelector 
{
     Function *fun = [[Function alloc]init];

    if ([fun respondsToSelector:aSelector]) {
        return fun;
    }
    return [super forwardingTargetForSelector:aSelector];
}

这样fun 对象就会执行 -(void)function 方法

方法三: 标准消息转发

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    if (aSelector == @selector(function)) {
        return  [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
    SEL selector = [anInvocation selector];

    Function *fun1 = [[Function alloc]init];

    Function *fun2 = [[Function alloc]init];

    if ([fun1 respondsToSelector:selector]) {

        [anInvocation invokeWithTarget:fun1];
    }
    if ([fun2 respondsToSelector:selector]) {
        
        [anInvocation invokeWithTarget:fun2];
    }
}

methodSignatureForSelector:用来生成方法签名,这个签名就是给forwardInvocation:中的参数anInvocation调用的。 方法三中我们自己新建方法签名,在forwardInvocation中用你要转发的那个对象调用这个对应的签名,这样也实现了消息转发。

方法二和方法三都是消息转发,方法二简单快速但是只能将消息转发给一个对象,方法三比较复杂速度慢但是可以将消息转发给多个对象