深入解析Halfrost-Field项目中的Objective-C Runtime:isa与Class机制

深入解析Halfrost-Field项目中的Objective-C Runtime:isa与Class机制

Halfrost-Field ✍🏻 这里是写博客的地方 —— Halfrost-Field 冰霜之地 Halfrost-Field 项目地址: https://gitcode.com/gh_mirrors/ha/Halfrost-Field

前言

Objective-C Runtime是iOS开发中最为核心的技术之一,理解它的工作原理对于深入掌握iOS开发至关重要。本文将从Halfrost-Field项目中的相关内容出发,系统性地剖析Objective-C Runtime中的isa指针和Class结构。

Runtime概述

Runtime(运行时)是Objective-C语言的核心机制,它是一套用C语言编写的API,为Objective-C提供了动态特性。与C语言等静态语言不同,Objective-C的方法调用是在运行时动态决定的,而非编译时。

Runtime系统主要实现了以下功能:

  • 动态创建类和对象
  • 消息传递和转发
  • 方法交换和方法调配
  • 关联对象
  • 方法实现的动态替换

NSObject的起源

在Objective-C中,几乎所有类都继承自NSObject(除了NSProxy)。NSObject的定义非常简单:

@interface NSObject <NSObject> {
    Class isa OBJC_ISA_AVAILABILITY;
}

这里的Class实际上是一个指向objc_class结构体的指针:

typedef struct objc_class *Class;

objc_class结构体的演变

在Objective-C 2.0之前,objc_class结构体定义如下:

struct objc_class {
    Class isa;
    Class super_class;
    const char *name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars;
    struct objc_method_list **methodLists;
    struct objc_cache *cache;
    struct objc_protocol_list *protocols;
};

而在Objective-C 2.0之后,objc_class的定义变得更加简洁:

struct objc_class : objc_object {
    Class superclass;
    cache_t cache;
    class_data_bits_t bits;
};

可以看到,新版中objc_class继承自objc_object,这意味着在Objective-C中,类本身也是一个对象

isa指针详解

isa指针是理解Objective-C对象模型的关键。每个对象都有一个isa指针,指向它的类。而类对象的isa指针则指向它的元类(metaclass)。

isa_t联合体

在Objective-C 2.0中,isa指针被定义为isa_t联合体:

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
    uintptr_t bits;
    struct {
        uintptr_t indexed           : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 33; // 类指针
        uintptr_t magic             : 6;
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19;
    };
};

这个联合体使用了位域技术来优化内存使用。各字段含义如下:

  1. indexed:是否启用isa指针优化
  2. has_assoc:对象是否有关联对象
  3. has_cxx_dtor:对象是否有C++或OC的析构器
  4. shiftcls:存储类指针的实际值
  5. magic:用于调试器判断对象是否初始化完成
  6. weakly_referenced:对象是否被弱引用
  7. deallocating:对象是否正在释放
  8. has_sidetable_rc:引用计数是否过大需要使用side table
  9. extra_rc:存储引用计数值减1后的结果

元类(Meta Class)

元类是类对象的类。在Objective-C中:

  • 实例对象的isa指向类
  • 类对象的isa指向元类
  • 元类对象的isa指向根元类
  • 根元类的isa指向自己

这种设计使得实例方法和类方法的调用机制能够保持一致:

  • 调用实例方法时,通过实例的isa找到类,然后在类的方法列表中查找
  • 调用类方法时,通过类的isa找到元类,然后在元类的方法列表中查找

Class结构详解

cache_t

cache_t用于缓存经常调用的方法,提高方法查找效率:

struct cache_t {
    struct bucket_t *_buckets;
    mask_t _mask;
    mask_t _occupied;
};

struct bucket_t {
    cache_key_t _key;
    IMP _imp;
};

缓存使用散列表实现,存储了方法选择器(SEL)和方法实现(IMP)的映射关系。

class_data_bits_t

class_data_bits_t是类的核心数据存储区域:

struct class_data_bits_t {
    uintptr_t bits;
};

它实际上指向一个class_rw_t结构体:

struct class_rw_t {
    uint32_t flags;
    uint32_t version;
    const class_ro_t *ro;
    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;
    Class firstSubclass;
    Class nextSiblingClass;
    char *demangledName;
};

class_ro_t存储了编译期确定的类信息:

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
    const uint8_t *ivarLayout;
    const char *name;
    method_list_t *baseMethodList;
    protocol_list_t *baseProtocols;
    const ivar_list_t *ivars;
    const uint8_t *weakIvarLayout;
    property_list_t *baseProperties;
};

在运行时,系统会将class_ro_t中的内容加载到class_rw_t中,并可以进行动态修改。

经典面试题解析

题目一:[self class]与[super class]

@implementation Son : Father
- (id)init {
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}
@end

输出结果都是"Son"。原因在于:

  1. [self class]会直接调用NSObject-class方法,返回对象的类
  2. [super class]虽然是从父类开始查找方法,但最终接收者(receiver)仍然是self

题目二:isKindOfClass与isMemberOfClass

BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];
BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];

输出结果是"1 0 0 0"。原因在于:

  1. isKindOfClass检查是否是指定类或其子类的实例
  2. isMemberOfClass严格检查是否是指定类的实例
  3. 类对象是元类的实例,不是自身的实例

总结

通过深入分析Halfrost-Field项目中的Runtime相关内容,我们可以得出以下结论:

  1. Objective-C中所有对象都是C语言结构体实现的
  2. 类本身也是一个对象(类对象)
  3. isa指针构成了对象-类-元类的完整体系
  4. 方法调用通过isa指针和缓存机制实现高效查找
  5. 类的数据存储采用了灵活的结构设计,支持运行时修改

理解这些底层机制,对于掌握Objective-C的面向对象特性、消息传递机制以及Runtime的高级用法都有重要意义。

Halfrost-Field ✍🏻 这里是写博客的地方 —— Halfrost-Field 冰霜之地 Halfrost-Field 项目地址: https://gitcode.com/gh_mirrors/ha/Halfrost-Field

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吕曦耘George

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值