以下是重构后的内容:
### dealloc方法触发时机及作用
官方给出的dealloc方法:
- 当一个对象retain count为0 (不再有强引用指向)时会触发dealloc。
- 注意直接把nil赋值给一个对象,不代表一定会触发dealloc。
### dealloc方法内部实现方法的调用时机
- 如果开发者实现了dealloc方法,那么先执行dealloc方法中的代码,执行完毕后在执行内部实现。
- 开发者并没有实现dealloc方法的情况下,直接执行系统内部方法调用。
### dealloc方法的作用及暴露原因
- dealloc的作用就是释放当前接收器占用的内存空间。
- 暴露出来是提供给开发者重写的,用来释放编码过程中用到的通知、Observer等需要手动管理释放的操作方法。
### dealloc方法内部实现流程
以下是来自于Apple官方开源代码objc4 -779的源码分析:
##### dealloc调用流程
1. 首先调用_objc_rootDealloc()函数。
2. 接下来调用rootDealloc()函数。
3. 判断是否可以被直接快速释放,判断的依据主要有5个,判断是否有以下五种情况:
- nonpointer:是否优化过isa指针。
- weakly_reference:是否存在弱引用指向。
- has_assoc:是否设置过关联对象。
- has_cxx_dtor:是否有cpp的析构函数(.cxx_destruct)。
- has_sidetable_rc:引用计数器是否过大无法存储在isa中。
4. 如果有以上五种任意一种,将会调用object_dispose()方法,做下一步的处理。如果没有之前五种情况的任意一种,则可以执行释放操作,C函数的free()。执行完毕。
以下是重构后的代码:
```cpp
void objc_clear_deallocating(id object) {
// Step 1: Check if hasCxxDtor, which means there is a destructor (deallocator) to be called.
if (hasCxxDtor(object)) {
call_object_cxxDestruct(object);
}
// Step 2: Check if hasAssocitatedObjects, which means there are associated objects to be removed.
if (hasAssocitatedObjects(object)) {
call_object_remove_associations(object);
}
// Step 3: Call objc_clear_deallocating() function.
call_objc_clear_deallocating(object);
}
// objc_clear_deallocating() function calling flow.
void call_objc_clear_deallocating(id object) {
// Step 4: Check if isa has been optimized. From arm64 architecture, the isa has been optimized into a union structure, so the result is usually optimized.
if (isOptimizedISA(object)) {
return;
}
// Step 5: Check if there are weak references or reference counts.
if (hasWeakReferencesOrReferenceCount(object)) {
call_clearDeallocating_slow();
} else {
call_weak_clear_no_lock();
}
}
// slow clear deallocating function calling flow.
void call_clearDeallocating_slow() {
// Steps from step 2 to step 4.
}
// weak clear no lock function calling flow.
void call_weak_clear_no_lock() {
// Remove all weak pointers pointing to this object.
call_weak_entry_remove();
}
```
以下是根据提供的代码重构的内容:
```c
/**
* Called by dealloc; nils out all weak pointers that point to the
* provided object so that they can no longer be used.
*/
void weak_clear_no_lock(weak_table_t *weak_table, id referent_id) {
objc_object *referent = (objc_object *)referent_id;
weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
if (entry == nil) {
/// XXX shouldn't happen, but does with mismatched CF/objc
//printf("XXX no entry for clear deallocating %p
", referent);
return;
}
// zero out references
weak_referrer_t *referrers;
size_t count;
if (entry->out_of_line()) {
referrers = entry->referrers;
count = TABLE_SIZE(entry);
}
else {
referrers = entry->inline_referrers;
count = WEAK_INLINE_COUNT;
}
for (size_t i = 0; i < count; ++i) {
objc_object **referrer = referrers[i];
if (referrer) {
if (*referrer == referent) {
*referrer = nil;
}
else if (*referrer) {
_objc_inform("__weak variable at %p holds %p instead of %p. " "This is probably incorrect use of " "objc_storeWeak() and objc_loadWeak(). " "Break on objc_weak_error to debug.
", referrer, (void*)*referrer, (void*)referent);
objc_weak_error();
}
}
}
weak_entry_remove(weak_table, entry);
}
```
开发者重写dealloc后,可以做以下事情:
1. 从NotificationCenter移除观察者(remove observer)和移除KVO。
2. 对于非ARC管理的资源,如CFRelease,进行释放操作。
3. 如果使用了RAC持有的disposable对象,可以在dealloc中调用dispose方法。
4. 移除手势识别器(removeGestureRecognizer),将需要从RunLoop中移除的对象从RunLoop中移除(addToRunLoop、removeFromRunLoop)。
5. 释放自己持有的dispatch_queue。
需要注意的是,不要做以下事情:
1. 不要调用[super dealloc],因为实际上想调用也调用不了。ARC编译器会自动调用,写了会直接报错程序无法运行。
2. 不要使用点语法(dot syntax)进行属性存取,建议使用_property进行存取。因为点语法会触发setter和getter方法,如果这些方法被重写,可能会实现一些未知的操作,从而涉及或者触发一些不应该在dealloc阶段做的事情,比如对属性做了KVO监听。
总之,开发者重写dealloc的主要目的是为了处理对象实例变量以外的资源。在重写此方法时,需要注意不要违反上述规则,以确保程序的正确性和稳定性。