2015-01-19 5 views
0

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

Мой код теперь выглядит следующим образом:

var timer = NSTimer() 
    let mainRunLoop:NSRunLoop = NSRunLoop() 

    func blurViewActive(gestureRecognizer:UIGestureRecognizer) { 
     if (gestureRecognizer.state == UIGestureRecognizerState.Began){ 
      println("STATE BEGAN") 
      var point = gestureRecognizer.locationInView(self.tv) 
      if let indexPath = self.tv.indexPathForRowAtPoint(point){ 
       let data = messageList[indexPath.row] as Messages 
       if let theCell = self.tv.cellForRowAtIndexPath(indexPath) as? TableViewCell{ 

        self.timer = NSTimer(timeInterval: 1, target: self, selector: "updateCounter", userInfo: nil, repeats: true) 

        self.mainRunLoop.addTimer(timer, forMode: NSRunLoopCommonModes) 
        mainRunLoop.run() 
       } 
     } 
} 
} 
    var counter = 10 
    func updateCounter(){ 
     if counter == 0{ 
     timer.invalidate() 
     }else{ 
     counter = --counter 
     println(counter) 
     } 
    } 

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

Любые предложения относительно того, как это будет сделано правильно, будут оценены.

+0

Я решительно полагаю, что 'mainRunLoop.run()' блокирует основной поток. Есть ли какая-то особая причина, по которой вы определяете свою собственную runloop, вместо того, чтобы просто использовать 'NSTimer (scheduleTimerWithTimeInterval: ...)', который автоматически добавляет таймер в главную runloop? –

+0

@MartinR Вы имеете в виду только замену self.timer ... на "self.timer = NSTimer.scheduledTimerWithTimeInterval (1, target: self, selector:" updateCounter ", userInfo: nil, repeatts: true)"? – martin

+0

Вот что я имел в виду. –

ответ

1

В коде есть две проблемы.

Прежде всего, mainRunLoop.run() блокирует основную нить. Использование вашей собственной runloop немного сложно, но на самом деле здесь не нужно. Вы можете создать таймер, работающий на главном runloop с

timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateCounter", userInfo: nil, repeats: true) 

и удалить mainRunLoop полностью.

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

Одно из возможных решений состоят в использовании двух словарей

var timerDict : [ NSIndexPath : NSTimer ] = [:] 
var counterDict : [ NSIndexPath : Int ] = [:] 

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

На длинном прессе, вы бы проверить первый словарь, если таймер уже активен для этой строки, а если нет, то создать и начать новый:

if timerDict[indexPath] == nil { 
     // No timer running for this row, start a new one: 
     counterDict[indexPath] = 10 
     timerDict[indexPath] = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateCounter:", 
      userInfo: indexPath, repeats: true) 
    } 

Обратите внимание, что путь индекс передан как userInfo: аргумент в таймер . Метод обратного вызова может затем получить индекс пути из переданного timer параметра и действовать соответственно:

func updateCounter(timer : NSTimer) { 
    if let indexPath = timer.userInfo as? NSIndexPath { 
     if var counter = counterDict[indexPath] { 
      if counter == 0 { 
       // stop timer and remove from dictionaries: 
       timer.invalidate() 
       timerDict.removeValueForKey(indexPath) 
       counterDict.removeValueForKey(indexPath) 
       println("indexPath: \(indexPath) DONE") 
      } else { 
       // decrement counter and update dictionary: 
       --counter 
       println("indexPath: \(indexPath) counter: \(counter)") 
       counterDict[indexPath] = counter 
      } 
     } 
    } 
} 

Отметим также (как @ gnasher729 сказал в своем ответе), правильный тип для обратного вызова таймера

func updateCounter(timer : NSTimer) { ... } 

с соответствующим селектором "updateCounter:" с задней двоеточием.

+0

Спасибо за хорошие предложения, однако это не решает проблему, которая одновременно запускает несколько таймеров/обратных отсчетов. – martin

+0

@ frank21: Я проверил вышеуказанный код, и всегда работает только один таймер, гарантированный проверкой 'if timer == nil {...}'. –

+0

Да, но я думаю, что я не объяснил, что я не понимаю проблему. Я хочу начать _multiple_ обратный отсчет. Поэтому, когда я выполняю мое длинное нажатие, и один таймер уже активен, я хочу начать дополнительный обратный отсчет. – martin

-1

Методы таймера всегда имеют параметр, являющийся самим объектом таймера. Поэтому «updateCounter» как селектор, вероятно, ошибочен.

+0

Не то, чтобы я рекомендую его, но обратные вызовы таймера без параметров работают. –

+0

... и неправильный селектор приведут к исключению «непризнанного селектора, отправленного в ...». –

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