method及相关方法分析

method及相关方法分析

转载请注名出处 http://blog.csdn.net/uxyheaven

本篇文章将探究一下objc里的关于方法的函数是如何实现的

首先看下方法的定义, Method 是一个objc_method结构体

objc_method

objc_method 是类的一个方法的描述

定义如下

Method class_getInstanceMethod(Class cls, SEL sel)
{
    if (!cls  ||  !sel) return NULL;

    return look_up_method(cls, sel, YES/*cache*/, YES/*resolver*/);
}

static Method look_up_method(Class cls, SEL sel,
                             BOOL withCache, BOOL withResolver)
{
    Method meth = NULL;
    // 1. 找缓存,有过有就返回
    if (withCache) {
        meth = _cache_getMethod(cls, sel, &_objc_msgForward_internal);
        if (meth == (Method)1) {
            // Cache contains forward:: . Stop searching.
            return NULL;
        }
    }
    // 2. 找自身
    if (!meth) meth = _class_getMethod(cls, sel);

    // 3. 找转发
    if (!meth  &&  withResolver) meth = _class_resolveMethod(cls, sel);

    return meth;
}

IMP class_getMethodImplementation(Class cls, SEL name)

返回cls的name方法的调用地址

定义如下

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
{
    if (!cls) return NO;

    rwlock_write(&runtimeLock);
    IMP old = addMethod(newcls(cls), name, imp, types ?: "", NO);
    rwlock_unlock_write(&runtimeLock);
    return old ? NO : YES;
}

static IMP addMethod(class_t *cls, SEL name, IMP imp, const char *types, BOOL replace)
{
    IMP result = NULL;

    rwlock_assert_writing(&runtimeLock);

    assert(types);
    assert(isRealized(cls));

    method_t *m;
    // 1. 在自己的类的方法列表里找这个方法
    if ((m = getMethodNoSuper_nolock(cls, name))) {
        // already exists
        if (!replace) {
            // 不取代, 返回 m->imp
            result = _method_getImplementation(m);
        } else {
            // 取代, 设置 cls 的 m 方法实现为 imp
            result = _method_setImplementation(cls, m, imp);
        }
    } else {
        // fixme optimize
        // 2. 建立一个method_list_t节点
        method_list_t *newlist;
        newlist = (method_list_t *)_calloc_internal(sizeof(*newlist), 1);
        newlist->entsize_NEVER_USE = (uint32_t)sizeof(method_t) | fixed_up_method_list;
        newlist->count = 1;
        newlist->first.name = name;
        newlist->first.types = strdup(types);
        if (!ignoreSelector(name)) {
            newlist->first.imp = imp;
        } else {
            newlist->first.imp = (IMP)&_objc_ignored_method;
        }

        // 3. 把newlist加到cls的方法列表里
        BOOL vtablesAffected = NO;
        attachMethodLists(cls, &newlist, 1, NO, &vtablesAffected);
        // 4. 刷新cls缓存
        flushCaches(cls);
        if (vtablesAffected) flushVtables(cls);

        result = NULL;
    }

    return result;
}

我们用class_addMethod时, replace == NO, 所以cls已经存在这个方法的时候添加是失败的

IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

替换cls的name方法的指针

void method_exchangeImplementations(Method m1_gen, Method m2_gen)
{
    method_t *m1 = newmethod(m1_gen);
    method_t *m2 = newmethod(m2_gen);
    if (!m1  ||  !m2) return;

    rwlock_write(&runtimeLock);

    if (ignoreSelector(m1->name)  ||  ignoreSelector(m2->name)) {
        // Ignored methods stay ignored. Now they're both ignored.
        m1->imp = (IMP)&_objc_ignored_method;
        m2->imp = (IMP)&_objc_ignored_method;
        rwlock_unlock_write(&runtimeLock);
        return;
    }

    // 交换2个方法的实现指针
    IMP m1_imp = m1->imp;
    m1->imp = m2->imp;
    m2->imp = m1_imp;

    if (vtable_containsSelector(m1->name)  ||
        vtable_containsSelector(m2->name))
    {
        // Don't know the class - will be slow if vtables are affected
        // fixme build list of classes whose Methods are known externally?
        flushVtables(NULL);
    }

    // fixme catch NSObject changing to custom RR
    // cls->setCustomRR();

    // fixme update monomorphism if necessary

    rwlock_unlock_write(&runtimeLock);
}

其实这里有个坑, Method是怎么来的呢, 通过class_getInstanceMethod,如果子类没有的话,会返回父类的方法, 如果这个时候在用method_exchangeImplementations替换,会把父类替的方法替换掉,这显然不是我们想要的.所以呢,我们的移魂大发通常是这么写

IMP method_getImplementation(Method m)
{
    return _method_getImplementation(newmethod(m));
}

static IMP _method_getImplementation(method_t *m)
{
    if (!m) return NULL;
    return m->imp;
}

IMP method_setImplementation(Method method, IMP imp)

设置方法的新的实现指针, 返回旧的实现指针

const char *method_getTypeEncoding(Method m)
{
    if (!m) return NULL;
    return newmethod(m)->types;
}
时间: 2024-08-03 11:19:48

method及相关方法分析的相关文章

web前端课程技术总结Node.js 使用方法及相关方法分析

Node.js 使用方法及相关方法分析 首先我们要了解什么是node.js? 官方解释是:node.js是一个基于Chrome v8引擎的javascript 运行环境.Node.js使用了一个事件驱动.非阻塞式 I/O的模型,使其轻量又高效.他是由c++编写的 所以速度很快 简单来说 就是一个js 的运行环境,所以他开发用的语言是js语言 ,通过node去编译你的js文件 node.js 的安装 1)npm i -g 全局(电脑只需安装一次) 2)npm i --save -dev /-D/(

Android中View绘制流程以及invalidate()等相关方法分析

前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴望了解 Android 框架层的网友,推荐这本书,希望你们能够在Android开发里学到更多的知识 . 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(measure).是否重新需要安置视图的位置(layout).以及是否需要重绘 (d

Android中View绘制流程以及invalidate()等相关方法分析(转载的文章,出处在正文已表明)

转载请注明出处:http://blog.csdn.net/qinjuning 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴望了解 Android 框架层的网友,推荐这本书,希望你们能够在Android开发里学到更多的知识 . 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(mea

Android-----View绘制流程以及invalidate()等相关方法分析 .

引自:http://blog.csdn.net/qinjuning/article/details/7110211 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴望了解 Android 框架层的网友,推荐这本书,希望你们能够在Android开发里学到更多的知识 . 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态

Android面试,View绘制流程以及invalidate()等相关方法分析

整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(measure).是否重新需要安置视图的位置(layout).以及是否需要重绘 (draw),其框架过程如下: measure()过程 主要作用:为整个View树计算实际的大小,即设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性:mMeasureWidth),每个View的控件的实际宽高

扩增子分析QIIME2-1简介和安装

QIIME2是微生物组分析流程QIIME(截止17.7.13被引7771次)的全新版(不是升级版),采用python3全新编写,并于2018年1月全面接档QIIME,是代表末来的分析方法标准(大牛们制定方法标准,我们跟着用就好了). 安装 安装方法比较简单,参照官网:https://docs.qiime2.org/2017.8/install/native/#install-miniconda 附1. 核心概念 原文链接:https://docs.qiime2.org/2017.8/concep

平摊分析 Amortized Analysis ------geeksforgeeks翻译

当偶尔一切操作很花的时间很慢,而大多数操作的时间都很快的时候,平摊分析的方法就很很好用了.在平摊分析中,我们分析一串操作并且可以得到最坏情况下的平均时间复杂度.例如hash table, disjoint set 和splay tree都是用平摊分析算法的. 举一个简单的hash table的插入算法,我们怎么来定义hash table的大小呢?这是一个时间和空间的权衡(trade-off).如果让hash table空间大的话,那搜索的时间会变慢,如果空间小,不一定能存的下数据. 解决这种权衡

Android Retrofit实现原理分析

retrofit有几个关键的地方. 1.用户自定义的接口和接口方法.(由动态代理创建对象.) 2.converter转换器.(把response转换为一个具体的对象) 3.注解的使用. 让我们跟随Api来看吧. RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(API_URL).build(); build()其内部实现是这样的: [代码]java代码: ? 1 2 3 4 5 6 7 8 public RestAda

JSONUtil.bean2Json()报Property &#39;key&#39; of class has no read method. SKIPPED的问题处理

错误警告信息描述: net.sf.json.JSONObject.defaultBeanProcessing(JSONObject.java:769) Property 'handler' of class com.vrv.cems.mgr.domain.Manager_$$_javassist_182 has no read method. SKIPPED 问题分析: JsonUtil.bean2Json(queryHistogramVO,new String[]{})); 将VO对象转换成J