NSTimer要求我将它添加到runloop

时间:2012-03-29 01:51:12

标签: ios objective-c nstimer nsrunloop

我想知道是否有人可以解释为什么要派遣回主队列并创建重复NSTimer我必须将它添加到RUN LOOP因为太火了?即使使用performselectorOnMainThread,我仍然需要将它添加到RUN循环才能触发它。

以下是我的问题示例:

#define queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define mainqueue dispatch_get_main_queue()

- (void)someMethodBeginCalled
{
    dispatch_async(queue, ^{
        int x = 0;
        dispatch_async(mainqueue, ^(void){
            if([_delegate respondsToSelector:@selector(complete:)])
                [_delegate complete:nil];
        });
    });
}

- (void)compelete:(id)object
{
    [self startTimer];

    //[self performSelectorOnMainThread:@selector(startTimer) withObject:nil waitUntilDone:NO];
}

- (void)startTimer
{
    NSTimer timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(callsomethingelse) userInfo:nil repeats:YES];

    //NSDefaultRunLoopMode
    [[NSRunLoop currentRunLoop] addTimer:_busTimer forMode:NSRunLoopCommonModes];
}

修改 我相信我措辞很差。如果我致电[[NSRunLoop currentRunLoop] addTimer:_busTimer forMode:NSRunLoopCommonModes];,我想知道为什么 startTimer需要someMethodBeginCalled。如果我不包括该行,则计时器不会触发。

例如,如果我从startTimer拨打viewDidLoad,我可以删除NSRunLoop行,计时器将每隔60秒触发一次。

6 个答案:

答案 0 :(得分:20)

以下是如何将NSTimer添加到runloop:

NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSDefaultRunLoopMode];

答案 1 :(得分:14)

您可以随时使用此方法:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(getBusLocation) userInfo:nil repeats:YES];

这会为你节省一条线,因为它会自动将它添加到运行循环中。

答案 2 :(得分:4)

因为,docs说:

  

计时器与运行循环一起使用。要有效地使用计时器,   你应该知道运行循环的运行方式 - 参见NSRunLoop和   线程编程指南。特别注意运行循环保留   他们的计时器,所以您可以在将计时器添加到计时器后释放计时器   运行循环。

这是Apple在为NSTimer编写代码时所做的设计决定(我确信他们有充分的理由这样做)并且我们无法绕过它。真的那么累吗?

答案 3 :(得分:3)

就像@sosborn说的那样,NSTimer取决于NSRunLoop,并且由于GCD队列创建的线程没有运行循环,NSTimer与{GCD不匹配1}}。

查看有关此问题的其他StackOverflow问题:Is it safe to schedule and invalidate NSTimers on a GCD serial queue?

为了解决这个问题,我实施了MSWeakTimerhttps://github.com/mindsnacks/MSWeakTimer(并在最后一个WWDC上由libdispatch工程师检查了实现!)

答案 4 :(得分:0)

在我的情况下,将计时器添加到runloop并不起作用。我不得不在主线程上创建计时器。我在MultipeerConnectivity委托中创建了这个线程。

    dispatch_async(dispatch_get_main_queue(), ^{
        self.timer = [NSTimer scheduledTimerWithTimeInterval:self.interval  invocation: self.invocation repeats:YES];
    });

答案 5 :(得分:0)

由于GCD队列创建了没有运行循环的线程,因此无法调用计时器方法

          <?php
    defined('BASEPATH') OR exit('No direct script access allowed');

    class Product_model extends CI_Model{

   public function __construct()
  {
   $this->load->database();
   parent::__construct();
   //Codeigniter : Write Less Do More
   }

    public function get_product()
   {
  #code
  $query=$this->db->get('products');
  return $query->result_array();
    }

    public function set_product($id=0)
   {
   #code
   // if($this->input->post('userSubmit')){
      $picture=array();
      $count=count($_FILES['picture']['name']);
      //Check whether user upload picture
      if(!empty($_FILES['picture']['name'])){

          foreach($_FILES as $value)
          {
            for($s=0; $s<=$count-1; $s++)
            {
              $_FILES['picture']['name']=$value['name'][$s];
    $_FILES['picture']['type']    = $value['type'][$s];
    $_FILES['picture']['tmp_name'] = $value['tmp_name'][$s];
    $_FILES['picture']['error']       = $value['error'][$s];
    $_FILES['picture']['size']    = $value['size'][$s];

    $config['upload_path'] = 'uploads/images/';
    $config['allowed_types'] = 'jpg|jpeg|png|gif';
    $config['file_name'] = $_FILES['picture']['name'];

    //Load upload library and initialize configuration
    $this->load->library('upload',$config);
    $this->upload->initialize($config);
          // print_r($value['name'][$s]);exit;
          if($this->upload->do_upload('picture')){
              $uploadData = $this->upload->data();
              $picture[] = $uploadData['file_name'];
          }
          else{
              $picture = '';
          }
        }
      }
      }//end of first if

      else{
          $picture = '';
      }

  $data=array(
    'product_name'=>$this->input->post('product_name')
  );
  $picture=array(
    'product_id'=>$this->db->get('products',$id),
    'picture_image'=>$picture
  );
  if ($id==0)
  {
    return $this->db->insert('products',$data);
    return $this->db->insert('images',$picture);
  }
  else {
    $this->db->where('id',$id);
    return $this->db->update('products',$data);
    return $this->db->update('images',$picture);
   }
   }
   }

然而,当在主队列上调度时,将调用timer方法,因为它将被添加到主线程运行循环中。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
   [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
       NSLog(@"Timer method from GCD main queue");
   }];

});