美文网首页
2019-05-13

2019-05-13

作者: iOneWay | 来源:发表于2019-05-13 13:42 被阅读0次

    1, class_getMethodImplementation
    如果一个消息被转发给一个实例对象,此时运行时会调用该方法返回一个方法指针。例如:[object func], 该语句调用时候,运行时会调用 class_getMethodImplementation(object.class, @selector(func)) 返回func的IMP

    IMP class_getMethodImplementation(Class cls, SEL name);
    //参数:cls:类; name: selector
    // 返回值:返回对应的函数指针。1,如果类的实例不响应选择器,则返回的函数指针将成为运行时消息转发机制的一部分;2,如果类的实例可以相应选择器,则返回对应函数指针 IMP。
    

    class_getMethodImplementation可能比method_getImplementation(class_getInstanceMethod(cls,name))更快。

    2,method_getImplementation
    返回方法的实现,即:方法IMP

    IMP method_getImplementation(Method m);
    

    3,Method
    非透明类型(即用typedef重命名的类型),表示一个方法在类中的定义

    typedef struct objc_method *Method;
    

    4,SEL
    非透明类型,表示一个方法的选择器, 代表方法在 Runtime 期间的标识符。本质上来说SEL其实就是一个方法名的char字符串表示,但是在使用的时候不能直接用char来代替SEL,而是应该使用使用从sel_registerName或Objective-C编译器指令@selector()返回的值。

    typedef struct objc_selector *SEL;
    //虽然 SEL 是 objc_selector 结构体指针,但实际上它只是一个 C 字
    //符串。在类加载的时候(即+load()方法执行的时候),编译器会生成与方法相对应的选择子,并
    //注册到 Objective-C 的 Runtime 运行系统。
    
    // 获取和创建SEL的两种方式
    SEL selA = @selector(setString:);
    SEL selB = sel_registerName("setString:");
    //控制台打印:
    (lldb) p selA
    (SEL) $1 = "setString:"
    (lldb) p selB
    (SEL) $2 = "setString:"
    // 所以本质上SEL是c字符串
    

    注意:不同类中相同名字的方法所对应的方法选择子是相同的,即使方法名字相同而变量类型不同也会导致它们具有相同的方法选择子。

    5,IMP
    表示一个指向函数实现的函数指针

    id (*IMP)(id, SEL, ...)
    /// 第一个参数:指向一个指向类实例对象的指针,如果是类方法则是指向元类的指针。
    // 第二个参数:是方法选择器
    // 之后的参数:方法需要的参数
    

    TODO:之后会补充object_selector, object_method等结构体

    6, class_getInstanceMethod
    返回指定的实例方法Method,如果该类没有找到对应Method则会去superclass找,如果依旧没有找到则返回NULL并且做消息转发。 注意:应当避免在+initialize中调用该方法。

    Method class_getInstanceMethod(Class cls, SEL name);
    ///cls: 指定的类;
    // name: 指定的方法标识符
    

    具体实现

    Method class_getInstanceMethod(Class cls, SEL sel)
    {
        if (!cls  ||  !sel) return nil;
    
        // This deliberately avoids +initialize because it historically did so.
    
        // This implementation is a bit weird because it's the only place that 
        // wants a Method instead of an IMP.
      // 应当避免在+initialize中调用该方法。
        Method meth;
    从缓存列表中查找,直到遇到_objc_msgForward_impcache入口,则不再继续查找。
        meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);
        if (meth == (Method)1) {
            // Cache contains forward:: . Stop searching.
            return nil;
        } else if (meth) {
            return meth;
        }
            
        // Search method lists, try method resolver, etc.
      //搜索方法列表,如果没有找到则运行时转发
        lookUpImpOrNil(cls, sel, nil, 
                       NO/*initialize*/, NO/*cache*/, YES/*resolver*/);
    
        meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);
        if (meth == (Method)1) {
            // Cache contains forward:: . Stop searching.
            return nil;
        } else if (meth) {
            return meth;
        }
    
        return _class_getMethod(cls, sel);
    }
    
    

    相关文章

      网友评论

          本文标题:2019-05-13

          本文链接:https://www.haomeiwen.com/subject/kzplaqtx.html