SEL IMP Method解读

本文详细解读了Objective-C中SEL、IMP和Method的概念与实现,包括它们的关系、初始化过程以及相关API的使用。通过分析源码,展示了如何根据SEL获取IMP,方法的查找过程,以及对象如何响应某个方法。最后提到了动态方法解析和消息转发,为后续深入理解Objective-C Runtime打下基础。
摘要由CSDN通过智能技术生成

我们知道iOS程序的入口函数在main.其实mian只是苹果给我们的”直观能够感受”的入口,在执行main之前,编译器已经帮我们做了相当多的事情.具体可以参考objc-os.h文件.Objective-C的Runtime库也是在main之前创建好的.我们关注sel_init()

SEL:

/************************************************************************ _objc_init* Bootstrap initialization. Registers our image notifier with dyld.* Called by libSystem BEFORE library initialization time**********************************************************************/void _objc_init(void){    static bool initialized = false;    if (initialized) return;    initialized = true;        // fixme defer initialization until an objc-using image is found?    environ_init();    tls_init();    static_init();    lock_init();    exception_init();        _dyld_objc_notify_register(&map_images, load_images, unmap_image);}

接口我们可以到sel_init()调用栈:

_|   _objc_init()  _|   _dyld_objc_notify_register    _|    map_images_nolock()       _|   sel_init()

在map_images_nolock()方法中我们看到在sel_init()下面有arr_init():

void arr_init(void) {    AutoreleasePoolPage::init();    SideTableInit();}

这个函数就是我们熟悉的AutoreleasePoolPage的初始化和全局SideTable的初始化,这个以后再分析.这里我们看一下sel_init()所做的工作:

/************************************************************************ sel_init* Initialize selector tables and register selectors used internally.**********************************************************************/void sel_init(size_t selrefCount){    // save this value for later    SelrefCount = selrefCount;    #if SUPPORT_PREOPT    builtins = preoptimizedSelectors();        if (PrintPreopt  &&  builtins) {        uint32_t occupied = builtins->occupied;        uint32_t capacity = builtins->capacity;                _objc_inform("PREOPTIMIZATION: using selopt at %p", builtins);        _objc_inform("PREOPTIMIZATION: %u selectors", occupied);        _objc_inform("PREOPTIMIZATION: %u/%u (%u%%) hash table occupancy",                     occupied, capacity,                     (unsigned)(occupied/(double)capacity*100));        }#endif    // Register selectors used by libobjc    #define s(x) SEL_##x = sel_registerNameNoLock(#x, NO)#define t(x,y) SEL_##y = sel_registerNameNoLock(#x, NO)    mutex_locker_t lock(selLock);        s(load);    s(initialize);    t(resolveInstanceMethod:, resolveInstanceMethod);    t(resolveClassMethod:, resolveClassMethod);    t(.cxx_construct, cxx_construct);    t(.cxx_destruct, cxx_destruct);    s(retain);    s(release);    s(autorelease);    s(retainCount);    s(alloc);    t(allocWithZone:, allocWithZone);    s(dealloc);    s(copy);    s(new);    t(forwardInvocation:, forwardInvocation);    t(_tryRetain, tryRetain);    t(_isDeallocating, isDeallocating);    s(retainWeakReference);    s(allowsWeakReference);    #undef s#undef t}

我们可以看到一些常见系统内置方法分别调用__sel_registerName()这个方法:

static SEL __sel_registerName(const char *name, bool shouldLock, bool copy) {    SEL result = 0;        if (shouldLock) selLock.assertUnlocked();    else selLock.assertLocked();        if (!name) return (SEL)0;        result = search_builtins(name);    if (result) return result;        conditional_mutex_locker_t lock(selLock, shouldLock);    if (namedSelectors) {        result = (SEL)NXMapGet(namedSelectors, name);    }    if (result) return result;    // No match. Insert.    if (!namedSelectors) {        namedSelectors = NXCreateMapTable(NXStrValueMapPrototype,                                           (unsigned)SelrefCount);    }    if (!result) {        // 初始化sel_alloc        result = sel_alloc(name, copy);                // 将selector 插入到NXMapTable 表中        // fixme choose a better container (hash not map for starters)        NXMapInsert(namedSelectors, sel_getName(result), result);    }        return result;}

这方法的作用是将selector注册到NXMapTable表中,如果selector不存在则调用selector初始化方法,然后将selector作为selector作为key,selector作为value存到NXMapTable哈希表中:

static SEL sel_alloc(const char *name, bool copy){    selLock.assertLocked();    return (SEL)(copy ? strdupIfMutable(name) : name);    }

在objc.h文件中我们可以看到SEL的声明:

/// An opaque type that represents a method selector.typedef struct objc_selector *SEL;

至此我们可以理解了,SEL就是一个表示方法的selector指针,映射方法的名字.

IMP:

/// A pointer to the function of a method implementation. #if !OBJC_OLD_DISPATCH_PROTOTYPEStypedef void (*IMP)(void /* id, SEL, ... */ ); #elsetypedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); #endif

从定义来看,IMP是一个指向实现函数的指针.IMP也是实现函数的入口,其和SEL的关系等以后将消息发送在细说.

Method:

method的声明结构:

typedef struct method_t *Method;

继续查看method_t的定义:

struct method_t {    SEL name;    const char *types;    MethodListIMP imp;        struct SortBySELAddress :        public std::binary_function    {        bool operator() (const method_t& lhs,                         const method_t& rhs)        { return lhs.name < rhs.name; }    };};

method_t中有两个我们熟悉的成员变量:SEL和MethodListIMP,看一下MethodListIMP:

#if __has_feature(ptrauth_calls)// Method lists use process-independent signature for compatibility.// Method caches use process-dependent signature for extra protection.//   (fixme not yet __ptrauth(...) because of `stp` inline asm in objc-cache.mm)using MethodListIMP = IMP __ptrauth_objc_method_list_imp;using MethodCacheIMP =    StorageSignedFunctionPointer;    #elseusing MethodListIMP = IMP;using MethodCacheIMP = IMP;#endif

MethodListIMP其实就是IMP,method可以理解为SEL(方法名称)和IMP(方法实现)相互对应的集合体.正常的情况一个SEL对应一个IMP,而SEL和IMP的绑定到运行时才确定的.

相关API

下面是NSObject.h和runtime.h文件为我们提供的有关SEL,IMP和Method相关的接口及说明:

runtim.h文件:

根据SEL获取实例Method指针

// 获取Method声明OBJC_EXPORT Method _Nullableclass_getInstanceMethod(Class _Nullable cls, SEL _Nonnull name)    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);    // 获取Method实现/****************************
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值