美文网首页
强引用(强持有)

强引用(强持有)

作者: 为了自由的白菜 | 来源:发表于2021-04-08 09:48 被阅读0次

    强引用(强持有)

    解决NSTimer强引用:

    • 重写didMoveToParentViewController方法
    - (void)didMoveToParentViewController:(UIViewController *)parent{  
        // 无论push 进来 还是 pop 出去 正常跑  
        // 就算继续push 到下一层 pop 回去还是继续  
        if (parent == nil) {  
           [self.timer invalidate];  
            self.timer = nil;  
            NSLog(@"timer 走了");  
        }  
    }  
    
    • 定义timer时,采用闭包的形式,因此不需要指定target
    - (void)blockTimer{  
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {  
            NSLog(@"timer fire - %@",timer);  
        }];  
    }  
    

    解决 强引用(强持有)

    依赖中介者模式,打破强持有,其中推荐思路四

    1. pop时在其他方法中销毁timer

    - (void)didMoveToParentViewController:(UIViewController *)parent{  
        // 无论push 进来 还是 pop 出去 正常跑  
        // 就算继续push 到下一层 pop 回去还是继续  
        if (parent == nil) {  
           [self.timer invalidate];  
            self.timer = nil;  
            NSLog(@"timer 走了");  
        }  
    }  
    

    2.中介者模式,即不使用self,依赖于其他对象

    //**********1、定义其他对象**********  
    @property (nonatomic, strong) id            target;  
    
    //**********1、修改target**********  
    self.target = [[NSObject alloc] init];  
    class_addMethod([NSObject class], @selector(fireHome), (IMP)fireHomeObjc, "v@:");  
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self.target selector:@selector(fireHome) userInfo:nil repeats:YES];  
    
    //**********3、imp**********  
    void fireHomeObjc(id obj){  
        NSLog(@"%s -- %@",__func__,obj);  
    }  
    
    - (void)dealloc{  
        [self.timer invalidate];  
        self.timer = nil;  
        NSLog(@"%s",__func__);  
    }  
    
    

    3.自定义封装timer

    //*********** .h文件 ***********  
    @interface CJLTimerWapper : NSObject  
    
    - (instancetype)cjl_initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;  
    - (void)cjl_invalidate;  
    
    @end  
    
    //*********** .m文件 ***********  
    #import "CJLTimerWapper.h"  
    #import <objc/message.h>  
    
    @interface CJLTimerWapper ()  
    
    @property(nonatomic, weak) id target;  
    @property(nonatomic, assign) SEL aSelector;  
    @property(nonatomic, strong) NSTimer *timer;  
    
    @end  
    
    @implementation CJLTimerWapper  
    
    - (instancetype)cjl_initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo{  
        if (self == [super init]) {  
            //传入vc  
            self.target = aTarget;  
            //传入的定时器方法  
            self.aSelector = aSelector;  
             
            if ([self.target respondsToSelector:self.aSelector]) {  
                Method method = class_getInstanceMethod([self.target class], aSelector);  
                const char *type = method_getTypeEncoding(method);  
                //给timerWapper添加方法  
                class_addMethod([self class], aSelector, (IMP)fireHomeWapper, type);  
                
                //启动一个timer,target是self,即监听自己  
                self.timer = [NSTimer scheduledTimerWithTimeInterval:ti target:self selector:aSelector userInfo:userInfo repeats:yesOrNo];  
            }  
        }  
        return self;  
    }  
    
    //一直跑runloop  
    void fireHomeWapper(CJLTimerWapper *wapper){  
        //判断target是否存在  
        if (wapper.target) {  
            //如果存在则需要让vc知道,即向传入的target发送selector消息,并将此时的timer参数也一并传入,所以vc就可以得知`fireHome`方法,就这事这种方式定时器方法能够执行的原因
            //objc_msgSend发送消息,执行定时器方法  
            void (*lg_msgSend)(void *,SEL, id) = (void *)objc_msgSend;  
             lg_msgSend((__bridge void *)(wapper.target), wapper.aSelector,wapper.timer);  
        }else{  
            //如果target不存在,已经释放了,则释放当前的timerWrapper  
            [wapper.timer invalidate];  
            wapper.timer = nil;  
        }  
    }  
    
    //在vc的dealloc方法中调用,通过vc释放,从而让timer释放  
    - (void)cjl_invalidate{  
        [self.timer invalidate];  
        self.timer = nil;  
    }  
    
    - (void)dealloc  
    {
        NSLog(@"%s",__func__);  
    }  
    
    @end  
    
    

    4. 利用NSProxy虚基类的子类

    //************NSProxy子类************  
    @interface CJLProxy : NSProxy  
    + (instancetype)proxyWithTransformObject:(id)object;  
    @end  
    
    @interface CJLProxy()  
    @property (nonatomic, weak) id object;  
    @end  
    
    @implementation CJLProxy  
    + (instancetype)proxyWithTransformObject:(id)object{  
        CJLProxy *proxy = [CJLProxy alloc];  
        proxy.object = object;  
        return proxy;  
    }  
    -(id)forwardingTargetForSelector:(SEL)aSelector {  
        return self.object;     
    }  
    
    
    //************解决timer强持有问题************  
    self.proxy = [CJLProxy proxyWithTransformObject:self];  
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self.proxy selector:@selector(fireHome) userInfo:nil repeats:YES];  
    
    //在dealloc中将timer正常释放  
    - (void)dealloc{  
        [self.timer invalidate];  
        self.timer = nil;  
    }  
    

    相关文章

      网友评论

          本文标题:强引用(强持有)

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