iOS进阶—Runtime源码解析:动态方法解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wtdask/article/details/84144071

GitHub参考
PS:参考GitHub分享的objc-runtime-master代码,及Runtime003代码

iOS进阶—目录


接上文iOS进阶—Runtime源码解析:消息发送

查看Runtime源码


// No implementation found. Try method resolver once.
//如果这个方法没有被发现,就会尝试一次动态方法解析,一次过后`goto retry`,再次执行我们上一篇文章中介绍的查找方式
    if (resolver  &&  !triedResolver) {
        runtimeLock.unlockRead();
        _class_resolveMethod(cls, sel, inst);
        runtimeLock.read();
        // Don't cache the result; we don't hold the lock so it may have 
        // changed already. Re-do the search from scratch instead.
        triedResolver = YES;
        goto retry;
    }

    // No implementation found, and method resolver didn't help. 
    // Use forwarding.
    //如果执行完上面的操作都没有找到,进入消息转发阶段
    imp = (IMP)_objc_msgForward_impcache;
    cache_fill(cls, sel, imp, inst);

 done:
    runtimeLock.unlockRead();

    return imp;

_class_resolveMethod方法

void _class_resolveMethod(Class cls, SEL sel, id inst)
{
    //如果不是元类,调用的实例方法 _class_resolveInstanceMethod
    if (! cls->isMetaClass()) {
        // try [cls resolveInstanceMethod:sel]
        _class_resolveInstanceMethod(cls, sel, inst);
    } 
    //如果是元类,调用 _class_resolveClassMethod
    else {
        // try [nonMetaClass resolveClassMethod:sel]
        // and [cls resolveInstanceMethod:sel]
        _class_resolveClassMethod(cls, sel, inst);
        if (!lookUpImpOrNil(cls, sel, inst, 
                            NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) 
        {
            _class_resolveInstanceMethod(cls, sel, inst);
        }
    }
}

代码示例:

main.m

#import <Foundation/Foundation.h>
#import "TZPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        [[TZPerson new] walk];
  
    }
    return 0;
}

TZPerson.m

#import "TZPerson.h"

@implementation TZPerson

//- (void) walk {
//    NSLog(@"%s", __func__);
//}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSLog(@"%s", __func__);
    return [super resolveInstanceMethod:sel];
}

@end

TZPerson类的walk方法没有被实现,方法调用没有被找到,会尝试一次动态方法解析,进入到+ (BOOL)resolveInstanceMethod:(SEL)sel;方法中。

在这里插入图片描述

执行一次没有被找到,接下来进入消息转发___forwarding__,再次执行resolveInstanceMethod

#import "TZPerson.h"
#import <objc/runtime.h>

@implementation TZPerson

//C语言方法
void walk() {
    NSLog(@"%s", __func__);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSLog(@"%s", __func__);
    
// 元类
// 实例对象、类对象、元类对象
    if (sel == @selector(walk)) {
        return class_addMethod(self, sel, (IMP)walk, "v@:");
    }
   
    return [super resolveInstanceMethod:sel];
}

@end

执行结果:

2018-11-19 10:37:00.898842+0800 Runtime001[1284:51608] +[TZPerson resolveInstanceMethod:]
2018-11-19 10:37:00.899171+0800 Runtime001[1284:51608] walk
Program ended with exit code: 0

在这里插入图片描述

在这里插入图片描述

使用OC的方式添加

#import "TZPerson.h"
#import <objc/runtime.h>

@implementation TZPerson

-(void) run {
    NSLog(@"%s",__func__);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSLog(@"%s", __func__);
    
    if (sel == @selector(walk)) {
        Method runMethod = class_getInstanceMethod(self, @selector(run));
        IMP runIMP = method_getImplementation(runMethod);
        const char* types = method_getTypeEncoding(runMethod);
        NSLog(@"%s", types);
        return class_addMethod(self, sel, runIMP, types);
    }
    return [super resolveInstanceMethod:sel];
}

@end

执行结果

2018-11-19 10:48:17.163472+0800 Runtime001[1339:56488] +[TZPerson resolveInstanceMethod:]
2018-11-19 10:48:17.163783+0800 Runtime001[1339:56488] v16@0:8 //16表示参数一共所占的字节数;@表示从第几个字节开始;:表示第8个字节
2018-11-19 10:48:17.163803+0800 Runtime001[1339:56488] -[TZPerson run]
Program ended with exit code: 0

类方法调用

ps:参考gitHub代码Runtime004

#import <Foundation/Foundation.h>
#import "TZPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        [TZPerson walk];
  
    }
    return 0;
}
#import "TZPerson.h"
#import <objc/runtime.h>

@implementation TZPerson

+ (void) run {
    NSLog(@"%s", __func__);
}

+ (BOOL)resolveClassMethod:(SEL)sel {
    
    if (sel == @selector(walk)) {
        Method runMethod = class_getClassMethod(self, @selector(run));
        IMP runIMP = method_getImplementation(runMethod);
        const char* types = method_getTypeEncoding(runMethod);
        NSLog(@"%s", types);
        return class_addMethod(object_getClass(self), sel, runIMP, types);
    }
    return [super resolveClassMethod:sel];
}

@end

猜你喜欢

转载自blog.csdn.net/wtdask/article/details/84144071