销毁的源头
调用-release,release会调用:
uintptr_t objc_object::sidetable_release(bool performDealloc)
sidetable_release():
以下是runtime源码 NSObject.mm
1584行
bjc_object::sidetable_release(bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.nonpointer);
#endif
SideTable& table = SideTables()[this];
bool do_dealloc = false;
//加锁
table.lock();
//获取当前对象所在的sidetable(一个hash表),在sidetable.refcnts(RefcountMap,一个map)中查到当前对象的迭代器
RefcountMap::iterator it = table.refcnts.find(this);
//接着判断迭代器是否是指向了sidetable的end
//如果是就代表找不到:
if (it == table.refcnts.end()) {
//将对象标记为“正在析构”
//标记需要dealloc
do_dealloc = true;
table.refcnts[this] = SIDE_TABLE_DEALLOCATING;
} else if (it->second < SIDE_TABLE_DEALLOCATING) {
//判断之前存储的引用计数值是否为 0,避免负数
//将对象标记为“正在析构”
//标记需要dealloc
// SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it.
do_dealloc = true;
it->second |= SIDE_TABLE_DEALLOCATING;
} else if (! (it->second & SIDE_TABLE_RC_PINNED)) {
//将引用计数减一
it->second -= SIDE_TABLE_RC_ONE;
}
//解锁
table.unlock();
if (do_dealloc && performDealloc) {
//调用对象的dealloc方法:
((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);
}
return do_dealloc;
}
如果调用了dealloc:
进行以下过程时,不能再创建有新的 __weak引用,否则会crash
递归调用父类的-dealloc
如果是 MRC 代码,则需要手动释放实例变量
最后调用NSObject的dealloc
NSObject的dealloc会调用
_objc_rootDealloc(self);
_objc_rootDealloc(id obj) NSObject.mm
1838行
_objc_rootDealloc(id obj)
{
//是否还活着 断言
assert(obj);
//调用 objc_object::rootDealloc()
obj->rootDealloc();
}
objc_object::rootDealloc() objc_object.h
415行
objc_object::rootDealloc()
{
//是否使用TaggedPointer优化 是直接人突然
if (isTaggedPointer()) return; // fixme necessary?
//不需要处理object_dispose的所有内容
if (fastpath(isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
!isa.has_cxx_dtor &&
!isa.has_sidetable_rc))
{
assert(!sidetable_present());
free(this);
}
else {
//调用object_dispose
object_dispose((id)this);
}
}
object_dispose(id obj) objc-runtime-new.mm
6313行
id object_dispose(id obj)
{
//是否为nil 直接返回
if (!obj) return nil;
//调用 void *objc_destructInstance(id obj)
objc_destructInstance(obj);
free(obj);
return nil;
}
void *objc_destructInstance(id obj) objc-runtime-new.mm
6290行
void *objc_destructInstance(id obj)
{
//如果不为nil 才处理
if (obj) {
//是否有析构函数 这个bool值取决于当前类以及父类往上是否有实例变量,如果有实例变量当前类就有.cxxDestruct,当前类或父类有此方法值=YES,都没有才=NO
bool cxx = obj->hasCxxDtor();
//是否有关联对象
bool assoc = obj->hasAssociatedObjects();
// This order is important.
//如果有析构函数 调用 void object_cxxDestruct(id obj)
if (cxx) object_cxxDestruct(obj);
//如果有关联对象 移除关联对象
if (assoc) _object_remove_assocations(obj);
//调用objc_clear_deallocating()清空引用计数表
obj->clearDeallocating();
}
return obj;
}
void object_cxxDestruct(id obj) objc-class.mm
473行
void object_cxxDestruct(id obj)
{
//如果为nil 直接retun
if (!obj) return;
//是否使用TaggedPointer优化 是直接return
if (obj->isTaggedPointer()) return;
//调用 static void object_cxxDestructFromClass(id obj, Class cls)
object_cxxDestructFromClass(obj, obj->ISA());
}
static void object_cxxDestructFromClass(id obj, Class cls) objc-class
447行
static void object_cxxDestructFromClass(id obj, Class cls)
{
void (*dtor)(id);
// Call cls's dtor first, then superclasses's dtors.
//往父类递归调用.cxxDestruct 直到hasCxxDtor=NO return结束
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);
}
}
}
.cxx_destruct
ARC下拥有实例变量才会有这个方法,通过Clang CodeGen生成,MRC都需要手动release所以不需要
ARC下会遍历当前对象所有的实例变量通过objc_storeStrong() release掉
具体实现过程:https://blog.sunnyxx.com/2014/04/02/objc_dig_arc_dealloc/
void objc_removeAssociatedObjects(id object) objc-runtime
635行
void objc_removeAssociatedObjects(id object)
{
if (object && object->hasAssociatedObjects()) {
_object_remove_assocations(object);
}
}
void _object_remove_assocations(id object) objc-references
316行
关联对象都存放在AssociationsHashMap中,以obj为key,以存放关联对象的ObjectAssociationMap为value,然后拿到ObjectAssociationMap中的所有ObjcAssociation对象,然后此对象调用ReleaseValue(),继而调用releaseValue,然后调用objc_release
void _object_remove_assocations(id object) {
vector< ObjcAssociation,ObjcAllocator > elements;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
if (associations.size() == 0) return;
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// copy all of the associations that need to be removed.
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
elements.push_back(j->second);
}
// remove the secondary table.
delete refs;
associations.erase(i);
}
}
// the calls to releaseValue() happen outside of the lock.
for_each(elements.begin(), elements.end(), ReleaseValue());
}
struct ReleaseValue {
void operator() (ObjcAssociation &association) {
releaseValue(association.value(), association.policy());
}
};
static void releaseValue(id value, uintptr_t policy) {
if (policy & OBJC_ASSOCIATION_SETTER_RETAIN) {
return objc_release(value);
}
}
void objc_clear_deallocating(id obj) NSObject.mm
1705行
void
objc_clear_deallocating(id obj)
{
assert(obj);
if (obj->isTaggedPointer()) return;
obj->clearDeallocating();
}
objc_object::clearDeallocating() objc-object.h
399行
inline void
objc_object::clearDeallocating()
{
if (slowpath(!isa.nonpointer)) {
// Slow path for raw pointer isa.
//调用sidetable_clearDeallocating()把对象的weak指针置nil,把对象的计数引用移除
sidetable_clearDeallocating();
}
else if (slowpath(isa.weakly_referenced || isa.has_sidetable_rc)) {
/判断是否有过弱引用 是否因为计数太大有多个sidetable
// Slow path for non-pointer isa with weak refs and/or side table data.
//调用clearDeallocating_slow();内部再分开判断各自实现sidetable_clearDeallocating的内容
clearDeallocating_slow();
}
assert(!sidetable_present());
}
相信看了上面的源码分析 对于下面这种图 父类有属性,关联对象,子类有属性关联对象,此时创建个[SubClass new]然后释放掉,这几个类的dealloc打印顺序是什么应该也清楚了,当然属性之间dealloc顺序,关联对象之间顺序还需要注意,同一个类多个属性的dealloc顺序是倒序,
- 属性列表的顺序:
分类属性1,分类属性2,类扩展属性1,类扩展属性2,类属性1,类属性2
- 属性的dealloc销毁顺序是:
类扩展属性2,类扩展属性1,类属性2,类属性1,然后再销毁父类的属性
关联对象添加的成员变量是先销毁子类的成员变量,在销毁父类的,在同一个类里添加的顺序不一定,因为底层是存储在无序map中,所以dealloc顺序不一定
屏幕快照 2018-11-15 下午2.00.48.png
runtime源代码下载地址
搜索objc4 选择数字最大的即为最新的(并不是最下面的就是最新的,看数字大小)