首先先明确两个关键字,IMP和SEL。
在一个OC的类中有.h文件和.m文件,一般来说一个是放@interface 一个是放@implementation,和这个类似SEL就是一个函数的声明方法,而IMP就是这个方法的实现,也就是一个函数的指针
接下来我们开始进行源码分析(源码取自源码下载的当前最新版709)
在runtime中,一般使用者会引入objc/message.h文件,这个文件用于消息分发,但是运行时对类的加载的文件是在objc/runtime.h文件中,所以首先我们来分析objc/runtime.h文件的代码
#if !OBJC_TYPES_DEFINED
/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method;
/// An opaque type that represents an instance variable.
typedef struct objc_ivar *Ivar;
/// An opaque type that represents a category.
typedef struct objc_category *Category;
/// An opaque type that represents an Objective-C declared property.
typedef struct objc_property *objc_property_t;
这是最上方的定义,定义了四个别名,分别是方法指针、变量指针、分类指针和属性指针(这里要说下变量指针和属性指针得区别:笔者也是根据源码的推测,以及网上的相关搜索,属性是用这一个类的属性,而变量是通过类实例化出来的对象的那一块真实的有存有实际值的变量)
接下来就是一个类的结构体的定义
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
这个类的结构体包含一个isa指针,父类指针、变量列表、方法列表、对象列表以及内存列表等
你在代码中没申明一个类出来,系统在运行时会自动通过这个结构体创建出来一个结构体对象,这一个对象就是描述着一个类的所有信息。比如:
@interface Person : NSObject
@end
@implementation Person
@end
创建出来这样一个类,系统会做的处理,就是创建出来一个结构体对象
{
super_class:NSObject,
name:Person,
........
}
接下来的这段代码是指出一个对象的数据类型是objc_object结构体
#ifdef __OBJC__
@class Protocol;
#else
typedef struct objc_object Protocol;
#endif
struct objc_protocol_list {
struct objc_protocol_list *next;
long count;
__unsafe_unretained Protocol *list[1];
};
这是一个链表形式,储存了所有对象的结构体指针,那么我们来看一下,对象又是一个什么样的结构:
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
// initIsa() should be used to init the isa of new objects only.
// If this object already has an isa, use changeIsa() for correctness.
// initInstanceIsa(): objects with no custom RR/AWZ
// initClassIsa(): class objects
// initProtocolIsa(): protocol objects
// initIsa(): other objects
void initIsa(Class cls /*nonpointer=false*/);
void initClassIsa(Class cls /*nonpointer=maybe*/);
void initProtocolIsa(Class cls /*nonpointer=maybe*/);
void initInstanceIsa(Class cls, bool hasCxxDtor);
// changeIsa() should be used to change the isa of existing objects.
// If this is a new object, use initIsa() for performance.
Class changeIsa(Class newCls);
bool hasNonpointerIsa();
bool isTaggedPointer();
bool isBasicTaggedPointer();
bool isExtTaggedPointer();
bool isClass();
// object may have associated objects?
bool hasAssociatedObjects();
void setHasAssociatedObjects();
// object may be weakly referenced?
bool isWeaklyReferenced();
void setWeaklyReferenced_nolock();
// object may have -.cxx_destruct implementation?
bool hasCxxDtor();
// Optimized calls to retain/release methods
id retain();
void release();
id autorelease();
// Implementations of retain/release methods
id rootRetain();
bool rootRelease();
id rootAutorelease();
bool rootTryRetain();
bool rootReleaseShouldDealloc();
uintptr_t rootRetainCount();
// Implementation of dealloc methods
bool rootIsDeallocating();
void clearDeallocating();
void rootDealloc();
private:
void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
// Slow paths for inline control
id rootAutorelease2();
bool overrelease_error();
#if SUPPORT_NONPOINTER_ISA
// Unified retain count manipulation for nonpointer isa
id rootRetain(bool tryRetain, bool handleOverflow);
bool rootRelease(bool performDealloc, bool handleUnderflow);
id rootRetain_overflow(bool tryRetain);
bool rootRelease_underflow(bool performDealloc);
void clearDeallocating_slow();
// Side table retain count overflow for nonpointer isa
void sidetable_lock();
void sidetable_unlock();
void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
bool sidetable_addExtraRC_nolock(size_t delta_rc);
size_t sidetable_subExtraRC_nolock(size_t delta_rc);
size_t sidetable_getExtraRC_nolock();
#endif
// Side-table-only retain count
bool sidetable_isDeallocating();
void sidetable_clearDeallocating();
bool sidetable_isWeaklyReferenced();
void sidetable_setWeaklyReferenced_nolock();
id sidetable_retain();
id sidetable_retain_slow(SideTable& table);
uintptr_t sidetable_release(bool performDealloc = true);
uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
bool sidetable_tryRetain();
uintptr_t sidetable_retainCount();
#if DEBUG
bool sidetable_present();
#endif
};
对象的结构体比较长,其中的属性和方法比较多,我们在这里只介绍主要的一些属性方法:
首先有一个私有的isa指针,isa是一个联合体,一般是一个指向该对象所属的类的objc_class对象的指针,在创建出来的对象需要调用成员变量或者成员方法时,会通过该isa指针向所属的类的objc_class对象发送消息请求运行方法,共有的成员方法可以通过指针直接调用。
然后继续看runtime.h文件,后续的代码都是一些以OBJC_EXPORT开头的函数,这些函数是一些工具函数,用于对运行时的类进行一些操作,经常使用的有几个函数:
/**
* Describes the instance variables declared by a class.
*
* @param cls The class to inspect.
* @param outCount On return, contains the length of the returned array.
* If outCount is NULL, the length is not returned.
*
* @return An array of pointers of type Ivar describing the instance variables declared by the class.
* Any instance variables declared by superclasses are not included. The array contains *outCount
* pointers followed by a NULL terminator. You must free the array with free().
*
* If the class declares no instance variables, or cls is Nil, NULL is returned and *outCount is 0.
*/
OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
class_copyIvarList函数,用于获取这个类的属性的列表。
OBJC_EXPORT Method class_getClassMethod(Class cls, SEL name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
class_getClassMethod方法,用于获取该类的类方法
OBJC_EXPORT Method class_getInstanceMethod(Class cls, SEL name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
class_getInstanceMethod方法,用于获取该类的实例方法
OBJC_EXPORT IMP class_getMethodImplementation(Class cls, SEL name)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
class_getMethodImplementation方法用于获取方法的实现
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
这是用于交换方法实现的函数,这个方法经常用到,用于对一个系统类,例如NSURL这样的类进行方法实现的改造,可以创建分类,并且在不引用该分类文件的情况下,改变这个类的方法实现。
这些方法还有很多,用到时可以查看源代码,都比较好理解,在这里就不多做赘述了。