runtime

作者: Leevi_w | 来源:发表于2020-03-07 18:27 被阅读0次

iOS中C++相关知识

什么是runtime

  • 在了解runtime之前,要知道Objective-C 是一门基于运行时的编程语言,这意味着所有方法、变量、类之间的链接,都会推迟到应用实际运行的最后一刻才会建立

  • Objective-C 的运行时本质上是一个库<objc/runtime.h>。它负责了 “Objective” 这个部分,OC中所有的面向对象编程都在runtime中实现

  • 它主要由 C 和汇编编写而成,其实现了诸如类、对象、方法调度、协议等等这些东西。它是完全开源的

对象 objc_object

声明
struct objc_object{
         Class isa OBJC_ISA_AVAILABILITY; 
    };
typedef struct objc_object *id;

实现
struct objc_object {
 private:
    isa_t isa; 
};

对象在runtime中是一个struct,通过isa(指针)与class(类)关联,这也是指针的意义

isa_t 指针

isa_tunion类型, “联合”是一种特殊的类,也是一种构造类型的数据结构,“联合”与“结构”有一些相似之处。但两者有本质上的不同。在结构中各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和(空结构除外,同时不考虑边界调整)。而在“联合”中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度
OC中已个指针的长度是47

析构函数(destructor)是成员函数的一种,它的名字与类名相同,但前面要加~,没有参数和返回值。

一个类有且仅有一个析构函数。如果定义类时没写析构函数,则编译器生成默认析构函数。如果定义了析构函数,则编译器不生成默认析构函数。

析构函数在对象消亡时即自动被调用。可以定义析构函数在对象消亡前做善后工作。例如,对象如果在生存期间用 new 运算符动态分配了内存,则在各处写 delete 语句以确保程序的每条执行路径都能释放这片内存是比较麻烦的事情。有了析构函数,只要在析构函数中调用 delete 语句,就能确保对象运行中用 new 运算符分配的空间在对象消亡时被释放

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits; // uintptr_t本质是 unsigned long  ,在处理器中占用8个字节,正好是64位的二级制
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};
image.png

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;  // 类的版本信息,默认为0
     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;

实现
struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    class_rw_t *data() const {  // class_rw_t 是bits 的存储地址
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }
}

// 判断是否为swift 查找第0位
// class is a Swift class from the pre-stable Swift ABI
#define FAST_IS_SWIFT_LEGACY    (1UL<<0)
// 判断是否为swift 查找第1位
// class is a Swift class from the stable Swift ABI
#define FAST_IS_SWIFT_STABLE    (1UL<<1)

// class or superclass has default retain/release/autorelease/retainCount/
//   _tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference
#define FAST_HAS_DEFAULT_RR     (1UL<<2)

// 64位 data pointer 数据指针  转为二进制47位    11111111111111111111111111111111111111111111000
#define FAST_DATA_MASK        0x00007ffffffffff8UL

class在runtime中的定义要比object复杂一些,但也是struct,同样也有isa,这里的isa关联的是父类,除了 NSObject这个类之外,其他super_class 的值永远不会为nil,因为 Objective-C 当中的其余类都是以某种方式继承自 NSObject 的。对于我们而言,更多的应该是关注变量列表 ivars、方法列表 methodLists和这个协议列表 protocols,这些我们可以通过runtime进行修改和读取, objc_class 继承 objc_object,具备对象所有特性

类别objc_category

typedef struct objc_category *Category
struct objc_category{
     char *category_name                         OBJC2_UNAVAILABLE; // 分类名
     char *class_name                            OBJC2_UNAVAILABLE;  // 分类所属的类名
     struct objc_method_list *instance_methods   OBJC2_UNAVAILABLE;  // 实例方法列表
     struct objc_method_list *class_methods      OBJC2_UNAVAILABLE; // 类方法列表
     struct objc_protocol_list *protocols        OBJC2_UNAVAILABLE; // 分类所实现的协议列表
}

Category同样也为struct,不能添加属性的关键也在此,没有ivars变量列表

变量 objc_ivar

struct objc_ivar {
    char *ivar_name;
    char *ivar_type;
    int ivar_offset;
}

方法 objc_method

struct objc_method {
    SEL method_name;
    char *method_types;
    IMP method_imp;
}

方法缓存 objc_cache

处理已调用方法缓存
struct objc_cache {
     unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE; //指定分配缓存bucket的总数。runtime使用这个字段确定线性查找数组的索引位置
     unsigned int occupied OBJC2_UNAVAILABLE; //实际占用缓存bucket总数
     Method buckets[1] OBJC2_UNAVAILABLE; //指向Method数据结构指针的数组,这个数组的总数不能超过mask+1,但是指针是可能为空的,这就表示缓存bucket没有被占用,数组会随着时间增长。
};

协议 objc_protocol

IMP

IMP本质上是函数指针 ,定义在objc.h文件,需要传入idSEL参数,id就是方法的self

typedef void (*IMP)(void /* id, SEL, ... */ );

runtime中提供了很多IMP操纵的API,如method_exchangeImplementations函数,Method Swizzling就是通过这个API 实现的

OBJC_EXPORT void
method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
  OBJC_EXPORT IMP _Nonnull
  method_setImplementation(Method _Nonnull m, IMP _Nonnull imp)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
  OBJC_EXPORT IMP _Nonnull
  method_getImplementation(Method _Nonnull m)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
  OBJC_EXPORT IMP _Nullable
 class_getMethodImplementation(Class _Nullable cls, SEL _Nonnull name)
[self class]   
传入当前实例变量
objc_msgSend()
[super class]  
也是传入当前实例变量
objc_msgSendSuper() 

初始化对象

new 等同于 alooc + init,因为内部都会通过callAlloc函数执行创建,

- (id)alloc {
    return _objc_rootAlloc(self);
}
id _objc_rootAlloc(Class cls) {
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
 }

 + (id)new {
   return [callAlloc(self, false/*checkNil*/) init];
}

// init 本质是返回 self
- (id)init {
    return _objc_rootInit(self);
}
id _objc_rootInit(id obj) {
    return obj; 
}

相关文章

相关文章

网友评论

      本文标题:runtime

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