iOS runtime随笔-消息转发机制

发布于:2025-06-26 ⋅ 阅读:(18) ⋅ 点赞:(0)

运行时的消息转发分三步, 当你调用了没有实现的方法时, 有机会通过runtime的消息转发机制补救一下

  1. resolveInstanceMethod/resolveClassMethod 这里可以动态去创建方法来解决Crash
  2. forwardingTargetForSelector ​​​​​第一步未解决, 就会走到这里, 可以给出一个Target去转发这个消息(方法调用)
  3. forwardInvocation ​​​​​​​上面2步都没有解决问题, 这里是最后一次机会, 利用methodSignatureForSelector返回一个方法签名, 在forwardInvocation中转发给对应的target

实例方法实现参考

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(testInstance)) {
        IMP imp = class_getMethodImplementation([self class], @selector(test));
        return class_addMethod([self class], sel, imp, "v@:");
    }
    return NO;
}

- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(testInstance)) {
        return self.realObj;
    }
    return [super forwardingTargetForSelector:aSelector];
}


- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(testInstance)) {
        return [[RealTestObject alloc] methodSignatureForSelector:aSelector];
    }
    return [super methodSignatureForSelector: aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL sel = anInvocation.selector;
    if ([self.realObj respondsToSelector:sel]) {
        [anInvocation invokeWithTarget:self.realObj];
        return;
    }
    [super forwardInvocation:anInvocation];
}

类方法实现参考

+ (BOOL)resolveClassMethod:(SEL)sel {
    if (sel == @selector(testClass)) {
//也可以通过block创建一个IMP去替代方法实现
//        IMP imp = imp_implementationWithBlock(^(void) {
//            NSLog(@"imp_implementationWithBlock");
//        });
        IMP imp = class_getMethodImplementation(objc_getMetaClass("TestObject"), @selector(testLogClass));
        class_addMethod(objc_getMetaClass("TestObject"), sel, imp, "v@:");
        return YES;
    }
    return NO;
}

+ (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(testClass)) {
        return [RealTestObject class];
    }
    return [super forwardingTargetForSelector:aSelector];
}

+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(testClass)) {
        return [RealTestObject methodSignatureForSelector:aSelector];
    }
    return [super methodSignatureForSelector:aSelector];
}

+ (void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL sel = anInvocation.selector;
    if (sel == @selector(testClass)) {
        [anInvocation invokeWithTarget:[RealTestObject class]];
        return;
    }
    [super forwardInvocation:anInvocation];
}


网站公告

今日签到

点亮在社区的每一天
去签到