• 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];
    
  • 相关阅读:
    面向对象与面向过程
    mul 指令
    Debug 的使用
    子域名扫描器
    div 指令
    C Primer Plus学习笔记(十三)- 结构和其他数据形式
    C Primer Plus学习笔记(十一)- 存储类别、链接和内存管理
    BugkuCTF WEB
    BugkuCTF 逆向
    C Primer Plus学习笔记(十)- 字符串和字符串函数
  • 原文地址:https://www.cnblogs.com/CoderHong/p/9389753.html
Copyright © 2020-2023  润新知