2014-10-19 4 views
3

Мое требование, что я хочу, чтобы вызвать API, чтобы попросить некоторую новую информацию от моего сервера каждые 6 секунд, поэтому я написал код, как показано ниже:Когда я должен применять Runloop к моей программе и почему?

MyBackgroundThread(){ 

    while(self.isStop){ 
     [self callMyAPI]; 
     [NSThread sleepfortimeinterval : 6 ]; 
    } 
} 

Но я узнаю, что сегодня есть способ предоставляемые библиотекой Foundation для записи цикла выполнения. Так что я могу переписать свой код, как показано ниже:

MyBackgroundThread(){ 

    NSTimer *timer = [NSTimer timerWithTimeInterval:6 target:self selector:@selector(callMyAPI) userInfo:nil repeats:YES]; 
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; 
    [timer release]; 
    while (! self.isCancelled) { 
     BOOL ret = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
    } 
} 

Однако, я не знаю, если это лучший способ делать свою работу, то мой оригинал? Если да, то почему? и как я могу проверить разницу в эффективности (или другом свойстве?) между этими двумя способами?

Спасибо!

ответ

3

Я думаю, что вообще не нужно создавать новый цикл запуска для таймера. Я хотел бы предложить один из двух подходов:

  1. NSTimer Расписания на основном цикле выполнения, но есть вызываемый метод затем направить запрос в фоновую очередь.

  2. Создать диспетчерский таймер, который планируется запустить в назначенной очереди отправки фона. Чтобы сделать это, создать диспетчерское свойство таймера:

    @property (nonatomic, strong) dispatch_source_t timer; 
    

    , а затем создать экземпляр и начать источник таймера отправки для запуска на вашей обозначенную очереди НОДА:

    dispatch_queue_t queue = dispatch_queue_create("com.domain.app.polltimer", 0); 
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 
    dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), kPollFrequencySeconds * NSEC_PER_SEC, 1ull * NSEC_PER_SEC); 
    
    dispatch_source_set_event_handler(self.timer, ^{ 
        <#code to be run upon timer event#> 
    }); 
    
    dispatch_resume(self.timer); 
    

Есть времена, что создает новый прогон цикл полезен, но в этом простом сценарии он не нужен.


Сказав это, вероятно, не имеет смысла использовать таймер для инициирования сети каждые шесть секунд. Вместо этого вы, вероятно, захотите начать следующий запрос через шесть секунд после завершения предыдущего . По ряду причин ваш сервер может не отвечать в течение шести секунд, и вы не хотите, чтобы в этих сценариях возникали параллельные запросы (что может произойти, если ваши запросы выполняются асинхронно).

Итак, я был бы склонен, что завершение блока callMyAPI сделать что-то же просто, как:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), queue, ^{ 
    <#code to issue next request#> 
}); 

Это устраняет необходимость таймеров (и пользовательских запуска циклов) полностью.


Наконец, если вам действительно необходимо обнаружить изменения системы с этой частотой, это может предложить совершенно другую архитектуру сервера. Например, если вы каждые шесть секунд проверяете, что-то изменилось на сервере, вы можете рассмотреть реализацию на основе сокетов или использовать push-уведомления. В обоих этих подходах сервер скажет клиентским приложениям, когда произойдет значительное событие, а не приложение, похожее на Барта Симпсона на заднем сиденье автомобиля, постоянно спрашивает: «Мы еще там?»

Соответствующая архитектура, вероятно, зависит от частоты, с которой данные сервера могут меняться и каковы требования к клиентскому приложению.

+0

Большое спасибо! Я пытаюсь использовать сокет сейчас, но я не знал, какое время подходит для создания нового цикла цикла, вместо того, чтобы просто использовать один созданный основной поток и отсоединить новый поток, чтобы справиться с событием после получения sth от источника? –

+0

Я мог бы склониться к установке другой runloop, если бы была какая-либо возможность негативно повлиять на основной цикл запуска. Но запуск чего-то каждые шесть секунд нигде не приближается к этому порогу. И, как я предложил, с помощью таймера GCD или 'dispatch_after', он сокращает узел Gordian. – Rob

 Смежные вопросы

  • Нет связанных вопросов^_^