• OC-底层实现


    class和id,NSObject的本质

    typedef struct objc_object NSObject;
    typedef struct objc_class *Class;
    typedef struct objc_object *id;
    
    • 1
    • 2
    • 3

    isa

    initIsa()

    正常来说是使用传进来的cls来初始化isa 因为在创建的时候每个对象会调用[[A alloc]init] init就会调用alloc alloc会传入self 这个self就是A的对象 就是型参 Class cls 比如
    bool dtor = cls->hasCxxDtor() 然后initIsa(cls,dtor)就可以用来初始化isa

    objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor)
    
    
    • 1
    • 2

    isa_t

    在initIsa中 isa_t newisa(0)
    是一个联合体 因为使用联合体+位域 所以只占用一个指针的空间
    除了存储指针值还保存了其他信息 比如

    nonpointer 占用1bit,标识是否开启isa优化.如果是一个指针值该位为0,则表示当前结构的值只是一个指针没有保存其他信息;如果为1,则表示当前结构不是指针,而是一个包含了其他信息的位域结构
    has_assoc 当前对象是否使用objc_setAssociatedObject动态绑定了额外的属性
    has_cxx_ctor是否有C++的构造函数
    has_cxx_dtor 是否含有C++或者OC的析构函数,不包含析构函数时对象释放速度会更快
    shiftcls 这个值相当于早期实现中的isa指针,是真实的指针值,在arm64处理器上只占据33位,可见其实在内存中可以用来存储对象指针的空间是很有限的
    magic 用于判断对象是否已经完成了初始化,在arm64中0x16是调试器判断当前对象是真的对象还是没有初始化的空间(在x86_64中该值为0x3b)
    weakly_referenced 是否是弱引用对象
    deallocating 对象是否正在执行析构函数(是否在释放内存)
    has_sidetable_rc 判断是否需要用sidetable去处理引用计数
    extra_rc 存储该对象的引用计数值减一后的结果. 当对象的引用计数使用extra_rc足以存储时
    unused 对象是否被释放
    has_sidetable_rc=0 当对象的引用计数使用extra_rc不能存储时has_sidetable_rc=1.可见对象的引用计数主要存储在两个地方:如果isa中extra_rc足以存储则存储在isa的位域中;如果isa位域不足以存储,就会使用sidetable去存储。
    参考网站

    内存问题

    创建

    alloc->_objc_rootAlloc->callAlloc->allocWithZone(和alloc)->_objc_rootAllocWithZone->initInstanceIsa
    init只是把对象返回

    销毁

    release会调用rootRelease
    如果newisa.nonpointer = 0 则调用sidetable_release方法
    sidetable_release会看是否符合条件

    if (do_dealloc  &&  performDealloc) {
            ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(dealloc));
    
    • 1
    • 2

    会判断sidetable中refcnt是否小于SIDE_TABLE_DEALLOCATING 如果小于则表示这个对象要被释放,则调用dealloc方法。如果不小于则直接执行refcnt -= SIDE_TABLE_RC_ONE;即refcnt-1操作。
    如果newisa.nonpointer = 1 则 对newisa.extra_rc进行-1操作,然后判断newisa.extra_rc是否有向下溢出,并执行对应操作。

    rootDealloc会调用object_dispose
    object_dispose调用free

    _object_dispose(id anObject)

    会调用

    objc_destructInstance(anObject);//会查看一下has_cxx_dtor是否有析构函数 如果有就调用他的析构 再查看是否有关联对象 如果有就取消关联 然后会做一个clearDeallocating不知道干嘛的
    
    • 1

    然后用freedObjectClass来设置Isa 将isa里面的信息都设置为nil

    anObject->initIsa(_objc_getFreedObjectClass ());
    
    • 1

    最后调用

    free(anObject);//调用dealloc
    
    • 1
    void *objc_destructInstance(id obj)
    void *objc_destructInstance(id obj) 
    {
        if (obj) {
            Class isa = obj->getIsa();
    
            if (isa->hasCxxDtor()) {
                object_cxxDestruct(obj);
            }
    
            if (isa->instancesHaveAssociatedObjects()) {
                _object_remove_assocations(obj);
            }
    
            objc_clear_deallocating(obj);
        }
    
        return obj;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    freedObjectClass
    static const void* freedObjectClass[12] =
    {
        Nil,				// isa
        Nil,				// superclass
        "FREED(id)",			// name
        0,				// version
        0,				// info
        0,				// instance_size
        nil,				// ivars
        nil,				// methodLists
        (Cache) &_objc_empty_cache,		// cache
        nil,				// protocols
        nil,			// ivar_layout;
        nil			// ext
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    鸿蒙LiteOs读源码教程+向LiteOS中添加一个系统调用
    基于Matlab卡尔曼滤波的IMU和GPS组合导航数据融合(附上源码+数据)
    Android kotlin内联函数(inline)的详解与原理
    【QT】QT自定义C++类
    Mysql事务
    web3.0时代分布式网络协议的异同
    ECMA各版本特性
    嵌入式软件设计之美-以实际项目应用MVC框架与状态模式(上)
    yaf常用开发工具:代码格式化&修复、语法检查、单元测试 —— k8s从入门到高并发系列教程 (五)
    图像噪声--添加噪声
  • 原文地址:https://blog.csdn.net/qq_43535469/article/details/126406758