zoukankan      html  css  js  c++  java
  • iOS 消息转发

    当我们调用一个不存在的方法时,就会报:unrecognized selector sent to instance **。消息接收者找不到对应的selector,这样就启动了消息转发机制,我们可以通过代码在消息转发的过程中告诉对象应该如何处理未知的消息,默认抛出上面的异常。

    1、对象在收到未知消息后,首先会调用 + (BOOL)resolveInstanceMethod:(SEL)sel 或者 + (BOOL)resolveClassMethod:(SEL)sel ,询问是否有动态方法来进行处理

    // 调用
    Person *p1 = [[Person alloc] init];
    [p1 performSelector:@selector(speak)];
    [Person performSelector:@selector(eat)];
    // Person.m
    #import <objc/runtime.h>
    void speak(id self,SEL _cmd) {
        NSLog(@"Now I can speak");
    }
    void eat(id self,SEL _cmd) {
        NSLog(@"eat......");
    }
    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
        NSLog(@"resolveInstanceMethod:%@",NSStringFromSelector(sel));
        if (sel == @selector(speak)) {
            class_addMethod([self class], sel, (IMP)speak, "vvv");
            return YES;
        }
        return [super resolveInstanceMethod:sel];
    }
    + (BOOL)resolveClassMethod:(SEL)sel
    {
        NSLog(@"resolveClassMethod:%@",NSStringFromSelector(sel));
        if (sel == @selector(eat)) {
            class_addMethod([self superclass], sel, (IMP)eat, "vvv");
            return YES;
        }
        return [super resolveClassMethod:sel];
    }
    添加动态方法

     当Person收到未知消息的时候,如果是实例方法会调用resolveInstanceMethod方法、类方法会调用resolveClassMethod方法,然后通过class_addMethod方法动态添加实现方法来解决未知消息,此时消息转发过程提前结束

    2、如果第一步返回的是NO,也就是没有动态新增实现方法就会调用第二步。使用 - (id)forwardingTargetForSelector:(SEL)aSelector 让别的类帮忙处理。

    //  调用
    //  ((void (*)(id, SEL))objc_msgSend)(p1, @selector(fly));
    [p1 performSelector:@selector(fly)];
    // Person.m
    - (id)forwardingTargetForSelector:(SEL)aSelector {
        NSLog(@"forwardingTargetForSelector:  %@", NSStringFromSelector(aSelector));
        Bird *bird = [[Bird alloc] init];
        if ([bird respondsToSelector: aSelector]) {
            return bird;
        }
        return [super forwardingTargetForSelector: aSelector];
    }
    // Bird.m
    - (void)fly
    {
        NSLog(@"I can fly");
    }
    让其他类处理这条消息

    3、如果前两种方法都不能处理未知消息,则使用下面方法

    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {
        NSLog(@"forwardInvocation: %@", NSStringFromSelector([anInvocation selector]));
        if ([anInvocation selector] == @selector(drink)) {
            Bird *b1 = [[Bird alloc] init];
            [anInvocation invokeWithTarget:b1];
        }
    }
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {
        NSLog(@"method signature for selector: %@", NSStringFromSelector(aSelector));
        if(aSelector == @selector(drink)) {
            return [NSMethodSignature signatureWithObjCTypes:"aaaa"];
        }
        return [super methodSignatureForSelector:aSelector];
    }
    最后一步

    如果最后消息还是未能处理,还会调用 - (void)doesNotRecognizeSelector:(SEL)aSelector ,可以在这个方法里做些处理,防止crash

    未知消息处理顺序

  • 相关阅读:
    FPGA边缘检测
    Luogu P5856 【「SWTR-03」Game】
    Luogu P4707 【重返现世】
    Weight Balanced Leafy Tree
    Luogu P4311 【士兵占领】
    Luogu P4174 【[NOI2006]最大获利】
    Luogu P1646 【[国家集训队]happiness】
    Luogu P4313 【文理分科】
    Luogu P4249 【[WC2007]剪刀石头布】
    Luogu P2754 【[CTSC1999]家园 / 星际转移问题】
  • 原文地址:https://www.cnblogs.com/chenyanliang/p/9299331.html
Copyright © 2011-2022 走看看