美文网首页Objective-C底层
iOS Objective-C底层 part4:die

iOS Objective-C底层 part4:die

作者: 破弓 | 来源:发表于2017-05-09 16:30 被阅读28次

    生对死,allocdealloc

    alloc经历了一些周折才调用calloc,开辟内存空间.
    dealloc也一样经历了一些周折才调用free,释放了内存空间.

    1. dealloc流程

    dealloc.png
    调用栈如上图.其实可以将分支合并:isa.nonpointer&&!isa.weakly_referenced&&!isa.has_assoc&& !isa.has_cxx_dtor&&!isa.has_sidetable_rc
    • 条件1:isa.nonpointer

    是否是支持nonpointerisa,不支持直接free;(不支持nonpointerisa,下面的条件都不必看)

    • 条件2:isa.has_cxx_dtor

    是否有C++的析构函数,为真,则要调用析构函数;

    • 条件3:isa.has_assoc

    是否有关联属性,为真,则要解除关联属性;

    • 条件4:isa.weakly_referenced

    是否有weak指针指向该对象,为真,则要将所有指向该对象的weak指针全部置为nil;

    • 条件5:isa.has_sidetable_rc

    是否开启了Sidetable来储存该对象的retainCount,为真,则要将该对象对应的Sidetable内储存的retainCount清除.

    5个条件全部走完,再调用free,收工.

    2. 哪里不对?

    问题1:ARC环境下不用书写对象对自己实例变量引用解除的代码,为什么流程中不见对自己实例变量解除引用的代码?

    答:一个方法,一个标记.

    @interface PGCustomClass : NSObject
    @property(nonatomic,copy)NSString * name;
    @end
    

    生成PGCustomClass对象时,看initInstanceIsa的参数:

    initInstanceIsa_1.png
    @interface PGCustomClass2 : NSObject
    
    @end
    

    生成PGCustomClass对象时,看initInstanceIsa的参数:

    initInstanceIsa_2.png
    • 一个标记

    很明显,带实例变量的类的obj->isa.has_cxx_dtor==1;
    很明显,不带实例变量的类的obj->isa.has_cxx_dtor==0;
    实例变量(是不是属性格式无所谓).
    obj->isa.has_cxx_dtor,追溯根源还是来自类的bits->flags.

    • 一个方法

    PGCustomClassPGCustomClass2内加入以下代码,打印方法列表:

    - (void)logMethods
    {
        unsigned int count;
        Method *methods = class_copyMethodList([self class], &count);
        for (int i = 0; i < count; i++)
        {
            Method method = methods[i];
            SEL selector = method_getName(method);
            NSString * name = NSStringFromSelector(selector);
            NSLog(@"方法名:%@",name);
        }
    }
    

    PGCustomClass:

    logMethods
    .cxx_destruct
    

    PGCustomClass2:

    logMethods
    

    很明显,带实例变量的类多出一个.cxx_destruct方法,是编译器加的.

    一个标记+一个方法==>如下效果:
    
    isa.has_cxx_dtor==1;
    └─object_cxxDestructFromClass
      └─.cxx_destruct
    

    isa.has_cxx_dtor==1;才会调用object_cxxDestructFromClass,进而调用.cxx_destruct.

    .cxx_destruct方法内就是做了对象对自己实例变量的引用解除

    static void object_cxxDestructFromClass(id obj, Class cls)
    {
        void (*dtor)(id);
    
        // Call cls's dtor first, then superclasses's dtors.
    
        for ( ; cls; cls = cls->superclass) {
            if (!cls->hasCxxDtor()) return; 
            dtor = (void(*)(id))
                lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
            if (dtor != (void(*)(id))_objc_msgForward_impcache) {
                if (PrintCxxCtors) {
                    _objc_inform("CXX: calling C++ destructors for class %s", 
                                 cls->nameForLogging());
                }
                (*dtor)(obj);
            }
        }
    }
    

    isa.has_cxx_dtor除了标记当前类是否有C++的析构函数外,被赋予了其他公用:标记对象是否有实例变量;

    为什么有实例变量的类才加标记方法呢?
    原因也很简单,因为只有这样的类生成的对象才会实例变量,对象有实例变量才需要解除引用.

    问题2:ARC环境下-dealloc内不能书写[super dealloc],为什么流程中也不见调用父类的dealloc?
    由上面的逻辑推算,[super dealloc]也是编译器加的.详情请戳


    文章参考:
    objc源码
    ARC下dealloc过程及.cxx_destruct的探究

    相关文章

      网友评论

        本文标题:iOS Objective-C底层 part4:die

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