iOS Runtime详解之SEL,Class,id,IMP,_cmd,isa,method,Ivar

来源:互联网 发布:win 写的java导入到mac 编辑:程序博客网 时间:2024/06/16 22:11

原文:http://blog.csdn.net/hello_hwc?viewmode=list 

前言:写了这么久的iOS博客,也是时候写写Rumtime的东西了,实际开发中用到的比较多的场景

  • 动态改变方法的执行体
  • Method Swizzling
  • NSSelectorFromString,NSClassFromString…
  • 动态添加属性(主要是类别)
  • 动态遍历属性和方法,动态为类添加方法

但是,基本的概念很重要,计划Runtime这个系列计划几篇文章

  • 讲讲一些基本概念(本文),例如SEL,Class,id,IMP等等
  • 详解iOS 中消息的传递机制,以及消息转发机制,内存分配,类对象,类元对象
  • Method Swizzling
  • 其他常见实际应用

什么是Runtime?

Objective C语言把能在运行期做的事情就推迟到运行期再决定。这就意味着,Objective C不仅需要一个编译器,而且需要一个运行期环境。这个运行期环境就是Runtime。

最直接的例子就是方法调用 
这样的一个OC方法

[receiver message]
  • 1

会被编译成

objc_msgSend(receiver, selector)
  • 1

这里,先记着receiver就是接受消息的对象,selector是执行消息的函数体名称,是个C的字符串。而不是像其他语言一样,直接编译成一个指向函数体的指针。

那么,在运行的时候,如何通过objc_msgSend(receiver, selector)找到实际的函数体呢?

That is Runtime!


为什么要写这样一篇基础的文章?

记得最开始接触Runtime的时候,感觉很乱,看得我最后都迷糊了,最后想了想,主要还是一些基本概念不清楚,搞不清楚这些名词是几乎不可能深入理解和应用Runtime的。

所以,我讲解Runtime的方式是,先搞清楚一些基本的关键词的底层定义,然后讲解消息处理以及转发机制,最后讲解示例。


SEL/objc_selector

objc_selector 

透明的数据结构,可以理解为C String

SEL 
源代码定义

typedef struct objc_selector *SEL;
  • 1
  • 2

也就是说,SEL是指向一个C String的指针。


id/objc_object

id - 指向一个类的实例对象 
底层代码定义

typedef struct objc_object *id;
  • 1

其中 
objc_object的底层定义

struct objc_object {    Class isa  OBJC_ISA_AVAILABILITY;};
  • 1
  • 2
  • 3

可以看到,objc_object中,只是保存了一个Class类型的isa。这里看不懂不要怕,先记着,对象中就是保存了一个指向Objective C中对应类的指针。


Class/objc_class

Class - 指向Objective C类对象(objc_class)的一个指针 
底层定义

typedef struct objc_class *Class;
  • 1

objc_class 
底层定义

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;/* Use `Class` instead of `struct objc_class *` */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

可以看到,这就是类对象结构体的定义,细心的同学可能发现了类对象里仍然有一个指针Class isa,先记着,这个isa指向的是类元对象。这个我会在下一篇文章里详细阐述


IMP

IMP-指向实际执行函数体的函数指针

#if !OBJC_OLD_DISPATCH_PROTOTYPEStypedef void (*IMP)(void /* id, SEL, ... */ ); #elsetypedef id (*IMP)(id, SEL, ...); #endif
  • 1
  • 2
  • 3
  • 4
  • 5

可以看到,这个函数体前两个参数是 id(消息接受者,也就是对象),以及SEL(方法的名字)


method/objc_method

method - 指向Objective C中的方法的指针

typedef struct objc_method *Method;
  • 1

其中

struct objc_method {    SEL method_name                                          OBJC2_UNAVAILABLE;    char *method_types                                       OBJC2_UNAVAILABLE;    IMP method_imp                                           OBJC2_UNAVAILABLE;}                                                            OBJC2_UNAVAILABLE;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

_cmd

SEL 类型的一个变量,Objective C的函数的前两个隐藏参数为self 和 _cmd


Ivar

ivar - objective C中的实例变量

typedef struct objc_ivar *Ivar;
  • 1
  • 2

可以看到变量的内存模型

struct objc_ivar {    char *ivar_name                                          OBJC2_UNAVAILABLE;    char *ivar_type                                          OBJC2_UNAVAILABLE;    int ivar_offset                                          OBJC2_UNAVAILABLE;#ifdef __LP64__    int space                                                OBJC2_UNAVAILABLE;#endif}                                                            OBJC2_UNAVAILABLE;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8