前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >系统框架--52:NSTimer会保留其目标对象

系统框架--52:NSTimer会保留其目标对象

作者头像
xy_ss
发布2023-11-22 08:33:54
1010
发布2023-11-22 08:33:54
举报
文章被收录于专栏:浮躁的喧嚣浮躁的喧嚣

NSTimer

计时器要和runloop相关联,runloop会触发任务。创建NSTimer时,可以将其“预先安排”在当前的runloop中,也可以创建好,然后再由开发人员自己调度。无论采用什么方式,只要把计时器放在循环里,它才能创建好触发的任务

代码语言:javascript
复制
//将其预先安排在当前的runloop中
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(run) userInfo:nil repeats:YES];

//停止timer
[self.timer invalidate];

注:target和selector参数表示计时器将在哪个对象上调用哪个方法,同时,计算机会保留其目标对象,直到计时器失效才会放弃此对象。

NSTimer的循环引用

创建定时器时,Student引用了定时器,在给定时器添加任务时,定时器保留了目标对象self,这里就出现了循环引用

代码语言:javascript
复制
#import <Foundation/Foundation.h>
@interface Student : NSObject
@property (nonatomic,strong) NSTimer *timer;
- (void)start;
- (void)end;
@end
--------------------
#import "Student.h"
@implementation Student
- (void)start{
    _timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(run) userInfo:nil repeats:YES];
}
- (void)end{
    [_timer invalidate];
    _timer = nil;
}
- (void)run{
    NSLog(@"--");
}
- (void)dealloc{
    NSLog(@"%s",__func__);
}
@end
--------------------
#import "ViewController.h"
#import "Student.h"
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    Student *stu = [[Student alloc]init];
    [stu start];
}
@end

解决这个循环引用的方法

  • Student不再引用定时器
  • 定时器不再保留目标对象self

Student不再引用定时器是不可行的,那么就只有第二种方法了。也就是合适的时候调用end方法。然而,合适的时机很难找到。假如这是一个验证码倒计时程序,你可以在倒计时结束时调用end方法。但是你不能确定用户一定会等倒计时结束才返回到上一级页面.或许你想在dealloc方法中使定时器失效,那你就太天真了。此时定时器还保留着当前控制器,此方法是不可能调用的,因此会出现内存泄漏。或许在倒计时程序中,你可以重写返回方法,先调用end再返回,但这不是一个好主意

这里采用block块的方法为NSTimer增加一个分类,具体细节看代码(程序员最好的语言是代码)。

代码语言:javascript
复制
#import <Foundation/Foundation.h>
@interface NSTimer (SSBlockSupport)
+ (NSTimer *)ss_scheduledTimerWithTimeInterval:(NSTimeInterval)inerval
                                        repeats:(BOOL)repeats
                                          block:(void(^)(NSTimer *timer))block;
@end
----------
#import "NSTimer+SSBlockSupport.h"
@implementation NSTimer (SSBlockSupport)
+ (NSTimer *)ss_scheduledTimerWithTimeInterval:(NSTimeInterval)inerval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block{
    return [NSTimer scheduledTimerWithTimeInterval:inerval target:self selector:@selector(ss_blcokInvoke:) userInfo:[block copy] repeats:repeats];
}
+ (void)ss_blcokInvoke:(NSTimer *)timer {
    void (^block)(NSTimer *timer) = timer.userInfo;
    if (block) {
        block(timer);
    }
}
@end
----------
#import <Foundation/Foundation.h>
@interface Student : NSObject
@property(nonatomic, strong) NSTimer *timer;
- (void)start;
- (void)end;
@end
----------
#import "Student.h"
#import "NSTimer+SSBlockSupport.h"
@implementation Student
- (void)start{
    __weak typeof(self) weakSelf = self;
    self.timer = [NSTimer ss_scheduledTimerWithTimeInterval:0.1 repeats:YES block:^(NSTimer *timer) {
        [weakSelf run];
    }];
}
- (void)end{
    [_timer invalidate];
    _timer = nil;
}
- (void)run{
    NSLog(@"--");
}
- (void)dealloc{
    [_timer invalidate];
    NSLog(@"%s",__func__);
}
@end
----------
#import "ViewController.h"
#import "Student.h"
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
   
    Student *stu = [[Student alloc]init];
    [stu start];
    
}
@end

在iOS10中,新的定时器即使不被引用,也可以正常运行,但是这依然会导致target不能释放,上面的方法依然十分有用。iOS10中,定时器的API新增了block方法,实现原理和这一样,只不过我这里用的是分类,而系统是在原始类中直接添加方法,最终的行为是一致的

代码语言:javascript
复制
#import "Student.h"
@implementation Student
- (void)start{
    __weak typeof(self) weakSelf = self;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        [weakSelf run];
    }];
}
- (void)end{
    [_timer invalidate];
    _timer = nil;
}
- (void)run{
    NSLog(@"--");
}
- (void)dealloc{
    [_timer invalidate];
    NSLog(@"%s",__func__);
}
@end
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-08-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NSTimer
  • NSTimer的循环引用
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档