


























最近更新了下以前写的TTGDeallocTaskHelper库,功能非常简单,就是在不改变原有代码的情况下,不用Runtime的Method Swizzling给任意对象添加任务Block,在对象dealloc的后期执行Block。使用时:
1 |
|
Github地址:https://github.com/zekunyan/TTGDeallocTaskHelper
一张图说明原理:

库的详细原理、限制、注意事项,为什么说“后期”执行,将在下文给出。
先给出几个使用案例。
比如你给一个第三方类对象添加了Notification通知,要在对象release后删除Notification的监听,就可以:
1 | [object ttg_addDeallocTask:^(__unsafe_unretained SomeClass *object, NSUInteger identifier) { |
有时你想快速验证一下一个类有没有释放,存不存在内存泄漏,比如一个ViewController返回后,就可以这么做:
1 | [someViewController ttg_addDeallocTask:^(__unsafe_unretained UIViewController *controller, NSUInteger identifier) { |
业务开发中,想监听某个事件什么时候销毁,就可以:
1 | [someEvent ttg_addDeallocTask:^(__unsafe_unretained SomeEvent *event, NSUInteger identifier) { |
是不是很方便!没有对原有的代码做任何侵入。
接下来看看实现原理。
在对象dealloc的时候做操作,有好几种方法:
dealloc方法,执行相关的任务。缺点是要修改用到类的地方为自己定义的子类对比了上面的四种方法后,选定用Associated Object的方式实现TTGDeallocTaskHelper。
总的思路是:
dealloc方法,在Associated Object释放的时候,批量执行之前添加的Block图示如下:

属性
上图中的TaskModel,就是库代码里面的TTGDeallocTaskModel类,包含三个属性:
1 | @property (nonatomic, assign) pthread_mutex_t lock; |
tasksDict保存要执行的任务Blocklock锁用来保证多线程下操作tasksDict的安全性target指向的是原对象,是unsafe_unretained的,保证始终不为nil,所以也建议不要在任务Block里面调用target的方法TTGDeallocTaskModel的tasksDict就是用来保存要执行的任务Block的,为了能在添加了以后删除,所以要以Key-Value的形式保存。
Key的类型是NSUInteger,全局自增,保证唯一。
为了保证自增的Key的线程安全,同时平衡性能,所以此处用OSAtomicIncrement64实现原子整型数自增:
1 |
|
为了保证NSMutableDictionary的多线程操作的安全,用pthread_mutex_t对添加Block的操作加锁:
1 | pthread_mutex_lock(&_lock); |
删除任务有两种,分别是删除一个identifier key对应的Block,和删除所有Block,同样,都要加锁保证线程安全:
1 |
|
最终在TaskModel被释放的时候,要批量执行所有添加的Block:
1 | - (void)dealloc { |
上面是TaskModel的部分,接下来是NSObject的。
给NSObject添加Categor NSObject (TTGDeallocTaskHelper),保存TTGDeallocTaskModel,封装调用。
Associated Object给对象添加TaskModel属性
用objc_setAssociatedObject实现给任意对象添加对应的TaskModel对象。
@synchronized保证多线程下TaskModel的唯一性
首次添加任务Block,会创建TaskModel,为了保证多线程下的唯一性,所以创建的部分要用@synchronized保护起来。
所以,添加任务Block的代码如下:
1 | - (NSUInteger)ttg_addDeallocTask:(TTGDeallocTaskBlock)taskBlock { |
直接获取当前对象的TaskModel对象,调用相应的方法即可,不再贴代码。
原理和实现说完了,接下来是库的限制与注意事项。
先来看看Associated Object在dealloc的什么时候释放。
NSObject对象dealloc的具体细节,sunnyxx在他的《ARC下dealloc过程及.cxx_destruct的探究》已经说的很清楚了。简单来说,就是对象dealloc的时候,最终会调用到objc_destructInstance方法上:
1 |
|
主要是3步:
object_cxxDestruct释放对象的ivar、property_object_remove_assocations释放对象的Associated Objectobjc_clear_deallocating重置所有指向对象的weak指针为空从dealloc的流程可知,Associated Object是在第二步被释放的,这个时候,原对象的属性已被release,并且,Associated Object对象自己的dealloc不一定在什么时候会被调用(比如加到了autorelease pool里面),所以,不建议在任务Block里面调用target原对象的方法。
什么时候Associated Object的释放能在对象属性release之前就好了=。=
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。