zoukankan      html  css  js  c++  java
  • iOS开发系列-定时器强引用问题

    概述

    iOS开发中常用的定时器NSTimerCADisplayLink

    NSTimer的创建方法有两个scheduledTimerWithTimeInterval开头另一个直接timerWithTimeInterval

    // scheduled开头创建的定时器默认已经添加到RunLoop中
    self.timer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(testTimer) userInfo:nil repeats:YES];
    
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(testTimer) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    

    CADisplayLink创建方法displayLinkWithTarget创建

    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(testLink)];
    [link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    

    定时器强引用问题

    在开发中在将通常将控制器作为定时器的target。一般我们在控制器的dealloc方法中停止定时器。

    - (void)dealloc
    {
        [self.timer invalidate];
    }
    

    由于将控制器设置为定时器的target,定时器会对控制器做强引用,造成控制器在pop出栈不会销毁,也不会调用控制器的的dealloc的方法,控制器pop后,定时器依然执行。

    避免设置target强引用解决方案

    方案一

    由于NSTimer可以通过block的方式直接设置定时任务可以避免设置target引起的强引用。

    [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
            // 定时任务
    }];
    

    方案二

    创建一个代理TimerProxy,将代理作为定时器target。

    TimerProxy.h
    
    #import <Foundation/Foundation.h>
    
    @interface HTTimerProxy : NSObject
    + (instancetype)timerProxyWithTaget:(id)target;
    @property (nonatomic, weak) id target;
    @end
    
    TimerProxy.m
    
    #import "HTTimerProxy.h"
    
    @implementation HTTimerProxy
    
    + (instancetype)timerProxyWithTaget:(id)target
    {
        HTTimerProxy *proxy = [[self alloc] init];
        proxy.target = target;
        return proxy;
    }
    
    // 利用runtime的消息转发
    - (id)forwardingTargetForSelector:(SEL)aSelector
    {
        return self.target;
    }
    @end
    
    

    NSTimer与CADisplayLink将HTTimerProx作为代理

    // scheduled开头创建的定时器默认已经添加到RunLoop中
    self.timer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:[HTTimerProxy timerProxyWithTaget:self] selector:@selector(testTimer) userInfo:nil repeats:YES];
    
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:[HTTimerProxy timerProxyWithTaget:self] selector:@selector(testLink)];
    [link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
  • 相关阅读:
    百度地图点击地图显示地址详情的默认方法怎么关闭,去掉百度地图api图标信息
    两个inline-block中间有空白,解决inline-block 元素之间的空白问题
    视频直播 object 标签属性详解
    2018.10.26 酷狗音乐校招前端一面经历(转)
    JS心得——判断一个对象是否为空
    echarts在tab切换时容器宽度设置为100%,只展示100px
    js生成[n,m]的随机数,js如何生成随机数,javascript随机数Math.random()
    vue2.0 日历日程表 ,可进行二次开发.
    浏览器兼容性问题解决方案 · 总结
    详解前端响应式布局、响应式图片,与自制栅格系统
  • 原文地址:https://www.cnblogs.com/CoderHong/p/9389753.html
Copyright © 2011-2022 走看看