iOS-延迟执行和定时器详解

iOS 中想实现方法的延迟执行和定时器功能,方法有很多,各有所长,所以在开发者,我们应该选择合适的方法。

延迟执行:

  • performSelector:afterDelay:
  • NSTimer
  • GCD的dispatch_after

定时器:

  • NSTimer
  • GCD的dispatch_source_t timer

一、延迟执行
01 - 使用performSelector:afterDelay:方式实现

官方:

// 默认只在主线程中执行,因为它默认添加到主runloop运行循环里面的NSDefaultRunLoopMode模式内
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;

// 默认只在主线程中执行,但可以选择其它多种的运行循环模式,包括:NSDefaultRunLoopMode,NSRunLoopCommonModes(the default, modal, and event tracking modes)
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSString *> *)modes;

事例:

    /**
     *  延迟2秒后执行 doSomething 方法,受UI事件的影响,比如UIScrollView的拖动操作
     */
    [self performSelector:@selector(doSomething) withObject:nil afterDelay:2.0];

    /**
     *  延迟2秒后执行 不受UI事件的影响
     */
    [self performSelector:@selector(doSomething:) withObject:nil afterDelay:2.0 inModes:@[NSRunLoopCommonModes]];

02 - 使用NSTimer方式实现,设置repeats参数(是否重复)为NO

官方:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

事例:

    // 01 手动添加到runloop运行循环中
    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(doSomething) userInfo:nil repeats:NO];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

    // 02 由系统自动添加到运行循环中
     [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(doSomething) userInfo:nil repeats:NO];

解析:上面两种NSTimer的方法是一样的,01是手动将timer添加到普通的运行循环里面,02的scheduledTimerWithTimeInterval方式,系统默认将timer添加到Mode:NSDefaultRunLoopMode 模式中,所以当01的Mode为NSDefaultRunLoopMode,两者等效
但01方式创建timer更加灵活,它可以选择不同的运行模式,包含:NSRunLoopCommonModes


03 - 使用GCD的dispatch_after方式实现

官方:

dispatch_after(dispatch_time_t when,
    dispatch_queue_t queue,
    dispatch_block_t block);

事例:

    __weak typeof(self) weakSelf = self;
    // 参数1:设置什么时候开始,默认从当前时间开始
    // 参数2:设置时间间隔,多久后执行
    // 参数3:设置在哪个线程执行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [weakSelf doSomething];
    });

解析:利用GCD 的 dispatch_after 不需要考虑runloop的运行循环,同时还可以选择在哪个线程中执行操作


三者比较和总结
1.NSTimer 和 performSelector方法都是基于runloop的

2.如果在子线程使用 performSelector和scheduledTimerWithTimeInterval 将是无效的
主线程的runloop默认处于激活状态,如果想在子线程添加他们,需要自己创建子线程的runloop并手动启动

3.NSTimer 和 performSelector的创建与撤销必须在同一个线程操作

4.内存管理有潜在泄露的风险
scheduledTimerWithTimeInterval方法将target设为A对象时,A对象会持有这个timer,但同时,timer会被当前的runloop所持有,如果对象处理不当,可能会造成内存泄露。

当使用NSTimer的scheduledTimerWithTimeInterval方法时,事实上此时Timer会被加入到当前线程的Run Loop中,且模式是默认的NSDefaultRunLoopMode。

而如果当前线程就是主线程,也就是UI线程时,某些UI事件,比如UIScrollView的拖动操作,会将Run Loop切换成NSEventTrackingRunLoopMode模式,在这个过程中,默认的NSDefaultRunLoopMode模式中注册的事件是不会被执行的。也就是说,此时使用scheduledTimerWithTimeInterval添加到Run Loop中的Timer就不会执行

所以为了设置一个不被UI干扰的Timer,我们需要手动创建一个Timer,然后使用NSRunLoop的addTimer:forMode:方法来把Timer按照指定模式加入到Run Loop中。这里使用的模式是:NSRunLoopCommonModes,这个模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的结合


二、定时器
01 - 使用NSTimer方式实现,设置repeats参数(是否重复)为YES
实现方式和上面的用法一样,不在累述的
02 - 使用GCD的dispatch_source_t timer方式实现
    __weak typeof(self) weakSelf = self;
    // dispatch_queue_t queue = dispatch_get_main_queue(); 主线程
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 全局子线程
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{

        [weakSelf doSomething:timer];

    });
    // 启动timer
    dispatch_resume(timer);
    // 暂停timer
    dispatch_suspend(timer);
    // 取消timer
    dispatch_source_cancel(timer);

使用注意:如果想要在dispatch_source_set_event_handler中实现对应的方法,必须引用block传过来的timer这个对象,否则无法执行.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值