• 在子线程中使用runloop,正确操作NSTimer计时的注意点 三种可选方法


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

    当每0.01秒进行一次repeat操作时,NSTimer是不准的,严重滞后,而改成0.1秒repeat操作,则这种滞后要好一些。

    导致误差的原因是我在使用“scheduledTimerWithTimeInterval”方法时,NSTimer实例是被加到当前runloop中的,模式是NSDefaultRunLoopMode。而“当前runloop”就是应用程序的main runloop,此main runloop负责了所有的主线程事件,这其中包括了UI界面的各种事件。当主线程中进行复杂的运算,或者进行UI界面操作时,由于在main runloop中NSTimer是同步交付的被“阻塞”,而模式也有可能会改变。因此,就会导致NSTimer计时出现延误。

    解决这种误差的方法,一种是在子线程中进行NSTimer的操作,再在主线程中修改UI界面显示操作结果;另一种是仍然在主线程中进行NSTimer操作,但是将NSTimer实例加到main runloop的特定mode(模式)中。避免被复杂运算操作或者UI界面刷新所干扰。

    方法一:

    在开始计时的地方:  

    1 if (self.timer) {     
    2 [self.timer invalidate];    
    3   self.timer = nil; 
    4 }  
    5 self.timer = [NSTimer timerWithTimeInterval:0.01 target:self selector:@selector(addTime) userInfo:nil repeats:YES];     
    6 [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

    [NSRunLoop currentRunLoop]获取的就是“main runloop”,使用NSRunLoopCommonModes模式,将NSTimer加入其中。

    方法二:

    开辟子线程:(使用子线程的runloop)

     1  NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread) object:nil]; 
     2  [thread start];
     3  - (void)newThread
     4  {
     5      @autoreleasepool
     6      {
     7          [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(addTime) userInfo:nil repeats:YES];
     8          [[NSRunLoop currentRunLoop] run];
     9      }
    10  }
    在子线程中将NSTimer以默认方式加到该线程的runloop中,启动子线程。

    方法三:

    使用GCD,同样也是多线程方式:

    声明全局成员变量

     1 dispatch_source_t _timers;
     2 uint64_t interval = 0.01 * NSEC_PER_SEC;
     3 dispatch_queue_t queue = dispatch_queue_create("my queue", 0);
     4 _timers = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
     5 dispatch_source_set_timer(_timers, dispatch_time(DISPATCH_TIME_NOW, 0), interval, 0);    
     6 __weak ViewController *blockSelf = self;
     7  dispatch_source_set_event_handler(_timers, ^()   
     8 {       
     9  NSLog(@"Timer %@", [NSThread currentThread]);       
    10 [blockSelf addTime]; 
    11 });
    12 dispatch_resume(_timers);
      

    然后在主线程中修改UI界面:

    1 dispatch_async(dispatch_get_main_queue(), ^{      
    2  self.label.text = [NSString stringWithFormat:@"%.2f", self.timeCount/100];    
    3 });
  • 相关阅读:
    自动发送邮件功能
    工作中常用的Android系统ADB命令收集
    商城系统必须知道的【订单、优惠金额、退货、实际营收】解释
    商城系统项目必须知道的专业数据指标
    接口加密思路
    Selenium使用Chrome模拟手机浏览器方法解析
    PHP上传图片基本代码示例
    iframe子页面获取父页面的点击事件
    javascript实现网页倒计时效果
    Crontab常用命令总结
  • 原文地址:https://www.cnblogs.com/widgetbox/p/10622585.html
Copyright © 2020-2023  润新知