美文网首页
iOS 为对象添加一个释放时触发的Block

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

作者: 只懂搬砖的z_bl | 来源:发表于2020-06-06 11:14 被阅读0次

    有时我们需要在一个对象生命周期结束的时候触发一个操作,希望当该对象dealloc的时候调用一个外部指定的block,但又不希望直接hook dealloc方法,这样侵入性太强了.怎么办呢?
    打个广告:问题验证demo里有相关的验证,可以去看看

    为什么不直接写个block的属性,在dealloc的时候调用呢?

    下面介绍一个简单的实现方法:

    通过一个category给外部暴露一个block注入的接口,内部将该block封装到一个寄生对象的dealloc中(Parasite),该寄生对象是以关联对象的形式与对象绑定。在对象dealloc的时候,触发对象关联对象的释放,从而释放寄生对象,寄生对象触发其dealloc同时触发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
    #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 {
        ///self是用来区分NSObject的子类的。
        
        ///此处有个同步操作,防止多线程数据竞争的干扰
        @synchronized (self) {
            static NSString *kAssociatedKey = @"kAssociatedKey";
            /// 数组,用于存放多个寄生对象
            NSMutableArray *parasiteList = objc_getAssociatedObject(self, &kAssociatedKey);
            if (!parasiteList) {
                parasiteList = [NSMutableArray new];
                objc_setAssociatedObject(self, &kAssociatedKey, parasiteList, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            }
            /// 创建寄生类 存放block
            Parasite *parasite = [Parasite new];
            parasite.deallocBlock = block;
            [parasiteList addObject: parasite];
        }
    }
    
    @end
    

    细节点:

    1. 寄生对象有一属性block,其实用于接收外部注入的block,好在寄生对象dealloc时,获取并调用

    2. 分类的实现中,关联对象为一可变数组,是为了让对象可以被注入多个释放回调(同时创建了用于存放释放回调的寄生对象)。统一由数组保存即可

    思考

    为什么要大费周章的加入runtime来注入block?对象直接创建一个block属性,在dealloc的时候调用,不也一样可以执行?

    个人有两个不成熟的想法:

    1. 简单点:此方法可以为对象注入多个不同block,不再需要重新定义,麻烦

    2. 鸿观点:此方法是一个不侵入类的做法。不需要关联到具体类(即不需要在每个类的dealloc中都操作一遍,此为侵入),比较通用。

    以上为个人浅见,欢迎各位大神参加讨论

    相关文章

      网友评论

          本文标题:iOS 为对象添加一个释放时触发的Block

          本文链接:https://www.haomeiwen.com/subject/snmazhtx.html