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];
    
  • 相关阅读:
    Window—mysql下载及安装
    postgresql 在windows下启动调试功能
    FASTREPORT自动换行及行高自适应
    如何卸载已经安装在delphi7中控件包?
    cxgrid使用三问1cxgrid 如何动态创建列2cxGrid 通过字段名取得列3cxGrid动态创建的列里动态创建事件的方法
    VirtualBox中Linux设置共享文件夹
    Android & iOS 启动画面制作工具(转自龟山Aone)
    PostgreSQL 基本数据类型及常用SQL 函数操作
    win10 安装Postgresql 服务不能启动报错
    TdxDbOrgChart 图标显示问题
  • 原文地址:https://www.cnblogs.com/CoderHong/p/9389753.html
Copyright © 2011-2022 走看看