iOS开发基础131-isa指针

iOS中isa指针是Objective-C对象内部的一个重要概念,它是实现对象与类之间关系的核心机制。深入理解isa指针对掌握Objective-C的底层运行机制和对象模型非常重要。

1. 什么是isa指针

每个Objective-C对象都有一个isa指针,它指向这个对象所属的类。类本身也有一个isa指针,指向其元类(metaclass)。元类本身又有一个isa指针,指向根元类,通常是NSObject的元类。

isa 指针的优化:非指针 isa

在现代 64 位架构中,isa 指针被设计成一个压缩的位域结构,以便更多的编码信息可以直接存储在 isa 指针中,而不仅仅是一个指向类对象的指针。

64 位系统下 isa 的优化结构

以 Apple 的开源 Objective-C 运行时为例,在 64 位系统上,具体的位域结构如下:

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

    Class cls;
    uintptr_t bits;
    struct {
        uintptr_t nonpointer        : 1;  // 指示是否启用了优化版 isa
        uintptr_t has_assoc         : 1;  // 是否有 associated 对象
        uintptr_t has_cxx_dtor      : 1;  // 是否有 C++ 析构函数
        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; // 一部分的引用计数
    };
};

2. isa 指针的实际用途

  • 类信息存储: 通过isa指针,运行时系统可以找到对象的类,并获取类的方法列表、属性列表等。
  • 类型检查和方法调用: 运行时通过isa指针实现类型检查和方法调用机制(动态绑定)。

在运行时,isa 指针用于以下几种目的:

2.1 动态类型识别

通过 isa 指针,运行时能够识别对象的实际类型。这对于动态消息传递系统至关重要。

- (void)someMethod {
    if ([self isKindOfClass:[NSString class]]) {
        NSLog(@"This object is a NSString or subclass");
    }
}

2.2 方法分派

Objective-C 运行时通过 isa 指针找到类对象,然后在类对象的方法缓存和方法列表中搜索方法实现。这就是动态绑定的机制。

void objc_msgSend(id self, SEL _cmd, ...) {
    Class cls = object_getClass(self);
    // 查找方法实现
    IMP imp = class_getMethodImplementation(cls, _cmd);
    // 调用方法实现
    imp(self, _cmd, ...);
}

3. isa 的非指针优化和引用计数

在非指针 isa 优化下,isa 中存储了引用计数的一部分,通过以下三个字段表示:

  • extra_rc: 额外的引用计数。当引用计数超过某个范围时,将额外的计数存储在 extra_rc 中。
  • has_sidetable_rc: 当引用计数超出了 extra_rc 能表示的范围时,会使用 SideTable 来存储更多的引用计数。

简化引用计数操作的方法:

增加引用计数

void objc_retain(id obj) {
    if (obj) {
        if (!obj->isa.nonpointer) {
            // 传统方式增加引用计数
            // objc::UnretainedUnsafe<objc_object> unretainedObject(obj);
            obj->retainCount++;
        } else {
            // 使用非指针 isa 增加引用计数
            if ((obj->isa.extra_rc) < 0xFFFFFF) {
                obj->isa.extra_rc++;
            } else {
                // 使用 SideTable 计数
                // sidetable_retain(obj);
            }
        }
    }
}

减少引用计数

void objc_release(id obj) {
    if (obj) {
        if (!obj->isa.nonpointer) {
            // 传统方式减少引用计数
            // objc::UnretainedUnsafe<objc_object> unretainedObject(obj);
            obj->retainCount--;
        } else {
            // 使用非指针 isa 减少引用计数
            if (obj->isa.extra_rc > 0) {
                obj->isa.extra_rc--;
            } else {
                // 使用 SideTable 计数
                // sidetable_release(obj);
            }
        }
    }
}

4. 结合源码理解 isa 指针

类与元类结构

Objective-C 的类结构与元类结构紧密相关,每个元类的 isa 都指向根元类,而根元类的 isa 指针又指向自身。

Class myClass = [NSObject class];
Class myMetaClass = object_getClass(myClass);

// 打印类信息
NSLog(@"Class: %@, MetaClass: %@", myClass, myMetaClass);

// 检查根元类
Class rootMetaClass = object_getClass(myMetaClass);
NSLog(@"RootMetaClass: %@", rootMetaClass);

// 元类的 isa 指针会指向根元类
NSLog(@"RootMetaClass isa: %@", *(Class *)((intptr_t)rootMetaClass & ~(1ULL<<62)));

使用 lldb 调试 isa 指针

可以使用 lldb 调试器查看对象的 isa 指针和相关信息,进一步理解底层结构:

(lldb) po [myObject class]
(lldb) p/x myObject->isa

总结

isa 指针是 Objective-C 运行时的核心机制之一,通过理解其内存布局和底层实现,我们可以更深入地了解动态类型系统、方法分派机制以及引用计数优化。这些知识有助于我们编写更高效、更可靠的 Objective-C 代码,同时也为调试和性能优化提供了强有力的工具。

posted @ 2024-07-18 11:28  Mr.陳  阅读(8)  评论(0编辑  收藏  举报