为对象添加一个释放时触发的block

3611次阅读  |  发布于5年以前

有时我们需要在一个对象生命周期结束的时候触发一个操作,希望当该对象dealloc的时候调用一个外部指定的block,但又不希望直接hook dealloc方法,这样侵入性太强了.下面贴一段非常简单的实现方式,通过一个category给外部暴露一个block注入的接口,内部将该block封装到一个寄生对象中(Parasite),该寄生对象在dealoc的时候触发block调用,所有的寄生对象通过runtime的AssociatedObject机制与宿主共存亡,从而达到监控宿主生命周期的目的.

实现方案时需要注意的几点:

代码实现如下。

NSObject+Guard.h:

#import <Foundation/Foundation.h>
@interface NSObject (Guard)
/**
 @brief 添加一个block,当该对象释放时被调用
 **/
- (void)guard_addDeallocBlock:(void(^)(void))block;
@end
NSObject+Guard.m

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

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8