Objective-C底层

iOS Objective-C底层 part4:die

2017-05-09  本文已影响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

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

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

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

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

是否开启了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的探究

上一篇下一篇

猜你喜欢

热点阅读