美文网首页
isa结构解析

isa结构解析

作者: ugpass | 来源:发表于2020-09-10 22:33 被阅读0次

1. isa初始化

iOS alloc原理分析 中会 initInstanceIsa中初始化isa,源码如下:

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    ASSERT(!isTaggedPointer()); 
    
    if (!nonpointer) {
        isa = isa_t((uintptr_t)cls);
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());

        isa_t newisa(0);

#if SUPPORT_INDEXED_ISA
        ASSERT(cls->classArrayIndex() > 0);
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
        newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif

        // This write must be performed in a single store in some cases
        // (for example when realizing a class because other threads
        // may simultaneously try to use the class).
        // fixme use atomics here to guarantee single-store and to
        // guarantee memory order w.r.t. the class index table
        // ...but not too atomic because we don't want to hurt instantiation
        isa = newisa;
    }
}

分析:
如果没有开启指针优化,则直接将类赋值给isa指针,即isa直接指向该类,isa = isa_t((uintptr_t)cls);
如果开启指针优化,则以另一种形式初始化isa指针。

2. isa结构

根据源码可知isa类型为isa_t联合体类型,源码如下:

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

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;                                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19

联合体:又名共用体,可以包含多个不同类型的成员。结构体和联合体的区别在于结构体的各个成员会占据不同的内存,而联合体的成员共用一块内存,各个成员的首地址相同。

所以在isa_t联合体中Class clsuintptr_t bits是互斥的。
typedef unsigned long uintptr_t; 所知,bits占据8字节,共64位,64位中存储的即ISA_BITFIELD宏定义中的内容。

uintptr_t nonpointer : 1; 是否对isa指针开启优化。0:纯isa指针 1:不只类对象地址,还包括了类信息,对象对引用计数等。
uintptr_t has_assoc : 1; 关联对象标识位 0:没有 1:存在。
uintptr_t has_cxx_dtor : 1; 是否有c++或objc的析构函数 如果有则需要调用析构逻辑,如果没有则可以更快释放对象。
uintptr_t shiftcls : 33; 存储类指针的值,开启指针优化时,有33位用来存放类指针。
uintptr_t magic : 6; 用于调试器判断当前对象是真的对象还是未初始化的空间。
uintptr_t weakly_referenced : 1; 标志对象是否被指向或曾经指向一个ARC的弱变量,没有弱引用的对象可以更快的释放。
uintptr_t deallocating : 1; 标志对象是否正在释放内存。
uintptr_t has_sidetable_rc : 1; 当引用计数大于10时,则需要借助该变量存储进位。
uintptr_t extra_rc : 19 表示该对象的引用计数减1,如果引用计数为10,则extra_rc为9,如果引用计数大于10,则需要借助has_sidetable_rc。

3. isa与类关联

- (Class)class {
    return object_getClass(self);
}

获取类对象,元类也是特殊的类对象

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

inline Class 
objc_object::getIsa() 
{
    if (fastpath(!isTaggedPointer())) return ISA();

    extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
    uintptr_t slot, ptr = (uintptr_t)this;
    Class cls;

    slot = (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
    cls = objc_tag_classes[slot];
    if (slowpath(cls == (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer)) {
        slot = (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
        cls = objc_tag_ext_classes[slot];
    }
    return cls;
}

inline Class 
objc_object::ISA() 
{
    ASSERT(!isTaggedPointer()); 
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    return (Class)(isa.bits & ISA_MASK);
#endif
}

获取类对象,即获取isa的指向。非taggedPointer的isa,最终返回return (Class)(isa.bits & ISA_MASK);

4. 对象的本质

//main.m
#import <Foundation/Foundation.h>
#import "LSPerson.h"

struct Person {
    char * name;
};

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        LSPerson *p1 = [[LSPerson alloc] init]; 
    }
    return 0;
}

通过clang -rewrite-objc main.m -o main.cpp将以上文件转成c++文件
NSObject底层结构为

struct NSObject_IMPL {
    Class isa;
};

LSPerson底层结构为

struct LSPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
};

因为LSPerson并没有其他成员变量,则直接继承自NSObject的结构体,所以继承自NSObject的对象都会有isa指针。

属性的setter方法都会调用objc_setProperty函数

void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) 
{
    bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
    bool mutableCopy = (shouldCopy == MUTABLE_COPY);
    reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
    if (offset == 0) {
        object_setClass(self, newValue);
        return;
    }

    id oldValue;
    id *slot = (id*) ((char*)self + offset);

    if (copy) {
        newValue = [newValue copyWithZone:nil];
    } else if (mutableCopy) {
        newValue = [newValue mutableCopyWithZone:nil];
    } else {
        if (*slot == newValue) return;
        newValue = objc_retain(newValue);
    }

    if (!atomic) {
        oldValue = *slot;
        *slot = newValue;
    } else {
        spinlock_t& slotlock = PropertyLocks[slot];
        slotlock.lock();
        oldValue = *slot;
        *slot = newValue;        
        slotlock.unlock();
    }

    objc_release(oldValue);
}

总结为retain新值,release旧值。

相关文章

  • isa结构解析

    我们知道绝大多数的OC对象都是继承自NSObject,而在NSObject的定义中只有一个属性---isa,而is...

  • isa结构解析

    1. isa初始化 在 iOS alloc原理分析 中会 initInstanceIsa中初始化isa,源码如下:...

  • 十七、Runtime之(一)isa详解

    1.isa结构 1.1 共用体掩码 ISA_MASK 1.2 isa内结构体位域解释 2.isa总结 isa本...

  • iOS源码解析:runtime<二> objc_ms

    iOS源码解析:runtime<一> isa,class底层结构窥探iOS方法调用的过程我们都很清楚,比如下面这个...

  • Runtime 学习资料汇总

    你真的了解 load 方法么? 从 NSObject 的初始化了解 isa 深入解析 ObjC 中方法的结构 从源...

  • iOS基础知识-类

    从 NSObject 的初始化了解 isa 代替 isa 指针的是结构体 isa_t, 这个结构体中"包含"了当前...

  • iOS 类的结构分析

    1. 类的初探 在isa结构解析中,自定义LSPerson 类继承自NSObject,重写成C++代码如下 str...

  • iOS - isa的初始化&指向分析

    isa结构及初始化分析 什么是isa,首先我们先看一下isa的结构: 由源码我们可以看出:isa的本质就是一个联合...

  • 面试复习-Runtime相关

    对象内部结构 isa + superclass + method cache + bits isa & bits ...

  • iOS内存管理方案

    __x86_64__环境调试 TaggedPointer 解析 判断 取值 NONPOINTER_ISA 解析 判...

网友评论

      本文标题:isa结构解析

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