有時(shí)我們需要在一個(gè)對(duì)象生命周期結(jié)束的時(shí)候觸發(fā)一個(gè)操作,希望當(dāng)該對(duì)象dealloc的時(shí)候調(diào)用一個(gè)外部指定的block,但又不希望直接hook dealloc方法,這樣侵入性太強(qiáng)了.下面貼一段非常簡(jiǎn)單的實(shí)現(xiàn)方式,通過一個(gè)category給外部暴露一個(gè)block注入的接口,內(nèi)部將該block封裝到一個(gè)寄生對(duì)象中(Parasite),該寄生對(duì)象在dealoc的時(shí)候觸發(fā)block調(diào)用,所有的寄生對(duì)象通過runtime的AssociatedObject機(jī)制與宿主共存亡,從而達(dá)到監(jiān)控宿主生命周期的目的.
注意事項(xiàng)
1.block觸發(fā)的線程與對(duì)象釋放時(shí)的線程一致,請(qǐng)注意后續(xù)操作的線程安全.
2.不要在block中強(qiáng)引用對(duì)象,否則引用循環(huán)釋放不了;
3.不要在block中通過weak引用對(duì)象,因?yàn)榇藭r(shí)會(huì)返回nil;
(根據(jù)WWDC2011,Session322對(duì)對(duì)象釋放時(shí)間的描述堤结,associated objects清除在對(duì)象生命周期中很晚才執(zhí)行烹困,通過被NSObject -dealloc方法調(diào)用的object_dispose()函數(shù)完成);
NSObject+Guard.h
#import <Foundation/Foundation.h>
@interface NSObject (Guard)
/**
@brief 添加一個(gè)block,當(dāng)該對(duì)象釋放時(shí)被調(diào)用
**/
- (void)guard_addDeallocBlock:(void(^)(void))block;
@end
NSObject+Guard.m
#import "NSObject+Guard.h"
#import <objc/runtime.h>
@interface Parasite : NSObject
@property (nonatomic, copy) void(^deallocBlock)(void);
@end
@implementation Parasite
- (void)dealloc {
if (self.deallocBlock) {
self.deallocBlock();
}
}
@end
@implementation NSObject (Guard)
- (void)guard_addDeallocBlock:(void(^)(void))block {
@synchronized (self) {
static NSString *kAssociatedKey = nil;
NSMutableArray *parasiteList = objc_getAssociatedObject(self, &kAssociatedKey);
if (!parasiteList) {
parasiteList = [NSMutableArray new];
objc_setAssociatedObject(self, &kAssociatedKey, parasiteList, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
Parasite *parasite = [Parasite new];
parasite.deallocBlock = block;
[parasiteList addObject: parasite];
}
}
@end