object-c编程tips-timer「建议收藏」

object-c编程tips-timer

大家好,又见面了,我是全栈君。

object-c定时器

object-c定时器会自己主动retain当前的使用者,假设不注意调用invalidate,则非常easy引起循环引用导致内存泄露。以下的思路提供了一套还算可行的解决方式。

举例:

常常在viewController中有可能有自己主动刷新界面的需求。 获取数据失败后。每隔10秒自己主动刷新又一次获取数据,这个时候使用NSTimer是一个非常方便的事情。普通情况下直接创建一个NSTimer的repeat对象,然后实现相应的timerFireMethod方法。 当用户主动点击返回button时候,此界面应该被释放。可是因为NSTimer retain了当前的viewController,导致界面内存泄露。 你可能会说在dealloc中调用invalidate,可是必须明确dealloc根本就不会调用,当然viewDidDisappear也一样不会被调用。

前一段时间看了effective object-c,学习了一种非常好的思想,现分享出来。

给NSTimer加入一个类别,使用block的方式传递timerFireMethod。代码例如以下:

@implementation NSTimer(LPBLocks)

+(NSTimer*) lpScheduleTimerWithTimerInternal:(NSTimeInterval)interval
                                       block:(void(^)())block
                                     repeats:(BOOL)repeats
{
    return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(lpTimerBlockInvoke:) userInfo:[block copy] repeats:repeats];
}
+(void)lpTimerBlockInvoke:(NSTimer*)timer
{
    void(^block)() = timer.userInfo;

    if(block){
        block();
    }
}
@end

这个scheduledTimer方法也会retain target,可是因为这是一个类方法。它保留的是类对象,因此也就不会有什么问题。

它传入要运行的block, 然后在回调函数中通过userInfo得到block,并运行。

改进:

这个已经是一个非常大的改进了。我们能够在代码中放心的传入block代码。只是细致思考一下。假设在block中引入了viewController的成员,并且timer又作为成员变量存在于viewController中。

比如例如以下的代码:

@interface LPNextViewController ()
{
    NSTimer*  refreshTimer;
}

这样viewController和refreshTimer又陷入了循环引用的逻辑圈里。当然能够在block中使用weak_self的方式避免循环引用,可是写起代码来总是有些不顺手。并且还必需要外部使用者显式的进行。

于是非常easy想到。应该封装到一个专门的LPTimer类中。它负责持有NSTimer。同一时候NSTimer的block使用LPTimer的weak版本号。

@interface LPTimer ()
{
    NSTimer* _pollTimer;

    //timer selector
    __weak id _weak_target;
    SEL _selector;
    id  _userInfo;
}
@end

-(void)scheduleTimerWithTimerInternal:(NSTimeInterval)interval
                                 target:(id)target
                               selector:(SEL)aSelector
                               userInfo:(id)userInfo
                                repeats:(BOOL)repeats
{
    __weak id weak_self = self;

    _weak_target = target;
    _selector = aSelector;
    _userInfo = userInfo;

    //借用第一个版本号的block思想
    //使用了第二层间接,调用_weak_target的aSelector方法。
    //这样能够把stopTimer给封装进去。外部不须要管理timer的stop。
    _pollTimer = [NSTimer lpScheduleTimerWithTimerInternal:1 block:^{
        [weak_self doTimer];
    } repeats:repeats];
}

上面的代码LPTimer持有NSTimer对象。而NSTimer运行的block使用的是weak_self。

它在timer触发的时候调用自身的doTimer方法。在doTimer中负责将方法传递给外部的使用者。

-(void)doTimer
{
    if ([_weak_target respondsToSelector:_selector]) {
        [_weak_target performSelector:_selector withObject:self];
    }
    else{
        DLog(@"WARNNING: unknown selector");
    }
}

_weak_target是外部的使用者。 外部的使用者能够将LPTimer看成是一个普通的对象即可,持有它也不会有什么问题。 LPTimer保留一个弱引用指向外部的使用者。在时间到timer触发的时候,会先调到NStimer的block中。然后传递到LPTimer的doTimer中。然后调用到_weak_target的selector中。

必须注意释放NStimer对象,在LPTimer释放的时候调用NSTimer的invalidate方法。

-(void)stopTimer
{
    DLog(@"");
    [_pollTimer invalidate];
}
-(void)dealloc
{
    [self stopTimer];
    DLog(@"");
}

事实上。使用者都是使用的LPTimer类,那么应该让LPTimer表现的和NSTimer的行为一模一样, 使用组合方式的适配器模式就能够轻松搞定。

总结:

主要的思想就是NSTimer会retain一个对象,如今让它retain类对象。

当时候到来进行触发的时候,由NSTimer类对象触发到Block中。继而触发到外部的LPTimer普通对象中。

在普通对象中我们就能够自由的进行处理了。使用weak_target使LPTimer弱引用外部使用者,断开外部使用者与LPTimer的关联。

使用weak_self断开LPTimer与NStimer的循环关联。 个人觉得还算不错的思想, 有须要的欢迎讨论。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/116393.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【SVN】SVN服务器搭建,客户端使用,在VS Code 中使用SVN

    【SVN】SVN服务器搭建,客户端使用,在VS Code 中使用SVN1.软件下载http://subversion.apache.org/packages.html#windows①VisualSVN服务端②TortoiseSVN客户端③Chinese,simplified语言包④vscode下载2.在vscode使用svn①在vscode里面下载TortoiseSVNforVSCode插件②配置svn环境变量和在……

    2022年7月19日
  • 6种不同画法画平行线_9.2 平行线和它的画法(练习)-2019-2020学年七年级数学下册同步精品课堂(青岛版)…[通俗易懂]

    6种不同画法画平行线_9.2 平行线和它的画法(练习)-2019-2020学年七年级数学下册同步精品课堂(青岛版)…[通俗易懂]资料简介:第九章平行线9.2平行线和它的画法精选练习答案一.选择题(共4小题)1.(2018春•沧州期中)在同一平面内,不重合的两条直线的位置关系是(  )A.平行B.相交C.平行或相交D.平行、相交或垂直【答案】C【详解】解:在同一平面内,不重合的两条直线只有两种位置关系,是平行或相交,所以在同一平面内,不重合的两条直线的位置关系是:平行或相交.故选:C.2.(2019春•铁西区校级月考)下列…

    2022年9月20日
  • Python 常用string函数

    Python 常用string函数字符串中字符大小写的变换1.str.lower()//小写>>>'SkatE'.lower()'skat

    2021年12月24日
  • 罗马时钟代码

    罗马时钟代码先看看效果图第一部分HTML页面代码<!DOCTYPEhtml><htmllang=”en”> <head> <metacharset=”UTF-8″> <metaname=”viewport”content=”width=device-width,initial-scale=1.0″> <met…

    2022年6月28日
  • 如何开发一个接口_网站接口开发

    如何开发一个接口_网站接口开发1、客户端请求加密、服务端请求解密2、防止重复提交一般是在数据库加状态,在status=0的状态下更新,更新完状态变为1,这样就可以防止重复提交———————————————————————————签名基本原理是通过key/secret的实现:1,服务器……

    2022年9月17日
  • LDAP统一认证服务解决方案[通俗易懂]

    LDAP是什么首先LDAP是一种通讯协议,LDAP支持TCP/IP。协议就是标准,并且是抽象的。在这套标准下,AD(ActiveDirectory)是微软出的一套实现。 那AD是什么呢?暂且把它理解成是个数据库。也有很多人直接把LDAP说成数据库(可以把LDAP理解成存储数据的数据库)。像是其他数据库一样,LDAP也是有client端和server端。server端是用来存放资源,client端用来操作增删改查等操作。 而我们通常说的LDAP是指运行这个数据库的服务器。 可以简单理解AD=LD

    2022年4月8日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号