2016-07-01 1 views
0

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

public class TimerManager{ 
    static let instance = TimerManager() 
    private var delegates = [TimerDelegate]() 
    var currentTimers = [TimerObject]() 

    public func timerAdded(timer: TimerObject){ 
     self.currentTimers.append(timer) 
     timer.timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(persistTimer(_:)), userInfo: "\(TimerManager.instance.currentTimers.count-1)", repeats: false) 
     timer.isRunning = true 
     for delegate in delegates{ 
      delegate.startTimer(self.currentTimers[self.currentTimers.count-1]) 
     } 
    } 

    @objc public func persistTimer(timer: NSTimer){ 
     if let indexString = timer.userInfo as? String{ 
      if let index = Int(indexString){ 
       if let currentTimer = self.currentTimers[safe: index]{ 
        if currentTimer.isRunning{ 
         currentTimer.timeDuration -= 1 
         for delegate in delegates{ 
          delegate.timerStarted(index) 
         } 
        } 
       } 
      } 
     } 

    } 

    public func addTime(timerId: Int, amount: Int){ 
     for delegate in delegates{ 
      delegate.addTimeToTimer(timerId, amount: amount) 
      UIApplication.sharedApplication().cancelLocalNotification(currentTimers[timerId].notification) 
      currentTimers[timerId].notification.fireDate = NSDate(timeIntervalSinceNow: Double(currentTimers[timerId].timeDuration)) 
     } 
    } 

    public func subtractTime(timerId: Int, amount: Int){ 
     for delegate in delegates{ 
      delegate.subtractTimeFromTimer(timerId, amount: amount) 
      UIApplication.sharedApplication().cancelLocalNotification(currentTimers[timerId].notification) 
      currentTimers[timerId].notification.fireDate = NSDate(timeIntervalSinceNow: Double(currentTimers[timerId].timeDuration)) 
     } 
    } 

    public func removeDelegate(removedDelegate: TimerDelegate){ 
     for i in 0..<delegates.count{ 
      if delegates[i] === removedDelegate{ 
       delegates.removeAtIndex(i) 
      } 
     } 
    } 

    public func cancelTimer(timerId: Int){ 
     let currentTimer = currentTimers[timerId] 
     currentTimer.timer.invalidate() 
     UIApplication.sharedApplication().cancelLocalNotification(currentTimer.notification) 
     currentTimers.removeAtIndex(timerId) 
    } 

    private init() {} 
} 

Это мой TimerManager singleton выше. Ниже мое удаление логика:

//Delete cell functionality 
    public override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { 
     if(editingStyle == .Delete){ 
      let screenSize: CGRect = UIScreen.mainScreen().bounds 
      let screenWidth = screenSize.width 
      let screenHeight = screenSize.height 
      let deletedTimer = TimerManager.instance.currentTimers[indexPath.row] 
      if (deletedTimer.isRunning){ 
       deletedTimer.timer.invalidate()// <-- invalidates all timers for some reason 
       UIApplication.sharedApplication().cancelLocalNotification(deletedTimer.notification) 
      } 
      TimerManager.instance.currentTimers.removeAtIndex(indexPath.row) 
      self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) 
      self.tableView.frame = CGRect.init(x: 0, y: 100, width: screenWidth, height: screenHeight * 0.0625 * CGFloat(TimerManager.instance.currentTimers.count)) 
     } 
    } 

Это, как я запустить таймер:

public func startTimer(timer: TimerObject) { 
     let newIndexPath = NSIndexPath(forRow: TimerManager.instance.currentTimers.count-1, inSection: 0) 
     self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Bottom) 
     let screenSize: CGRect = UIScreen.mainScreen().bounds 
     let screenWidth = screenSize.width 
     let screenHeight = screenSize.height 
     self.view.frame = CGRectMake(0, 100, screenWidth, screenHeight * 0.0625 * CGFloat(TimerManager.instance.currentTimers.count)) 
     self.view.alpha = 0.95 

    } 

Это то, что мой TimerObject состоит из:

public class TimerObject{ 
    var alreadySet = false 
    var isRunning = false 
    var timer = NSTimer() 
    var timeDuration = Int() 
    var timerString = String() 
    var doneString = String() 
    let notification = UILocalNotification() 

    init(timeDuration: Int, timerString: String, doneString: String){ 
     self.timeDuration = timeDuration 
     self.timerString = timerString 
     self.doneString = doneString 
     notification.alertBody = doneString 
    } 
} 

инстанцирования TimerObject:

private func setTextLinks(string: String){ 
     if let timersForInstruction = parsedOutTimers{ 
      stepTextView.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.redColor()] 
      for timer in timersForInstruction{ 
       stepTextView.addLink(string.substringFromRange(timer.range)) { 
        let newTimer = TimerObject.init(timeDuration: timer.lowerBound * 60, timerString: self.stepTitle 
        newTimer.notification.fireDate = NSDate(timeIntervalSinceNow: Double(newTimer.timeDuration)) 
        TimerManager.instance.timerAdded(newTimer) 
       } 
      } 
      stepTextView.processLinks() 
     } 
    } 

Я бы сказал, что это, где он используется:

//where we update the cells 
    public func timerIsRunning(timerIndex: Int){ 
     if let currentTimer = TimerManager.instance.currentTimers[safe: timerIndex]{ 
      guard let cell = self.tableView.cellForRowAtIndexPath(NSIndexPath.init(
       forRow: timerIndex, 
       inSection: 0)) as? TimerCell else { return } 
      if currentTimer.timeDuration > 0{ 
       currentTimer.timeDuration -= 1 
       cell.timerDisplay.text = "\(currentTimer.timerString) \t\t\t - \(currentTimer.timeDuration/60):\((currentTimer.timeDuration % 60).format("02")) + " 
       cell.timerDisplay.processLinks() 
      }else if(currentTimer.timeDuration <= 0){ 
       currentTimer.isRunning = false 
       cell.timerDisplay.text = "Finished" 
       currentTimer.timer.invalidate() 
       currentTimer.notification.fireDate = NSDate(timeIntervalSinceNow: 0) 
       currentTimer.notification.alertBody = currentTimer.doneString 
       currentTimer.notification.alertAction = "Ok" 
       if(self.isBeingPresented()){ 
        NSNotificationCenter.defaultCenter().postNotificationName("timerDidFinish", object: currentTimer.notification.alertBody) 
       } 
       if(UIApplicationState.Background == UIApplication.sharedApplication().applicationState){ 
        UIApplication.sharedApplication().scheduleLocalNotification(currentTimer.notification) 
       } 
      }else{ 
       //handle pause 
      } 
     } 

    } 

Я искренне надеюсь, что это достаточно информации, чтобы работать. Любые решения или альтернативы очень помогли бы.

+0

Никогда не делать 'таймер вар = NSTimer()'. Вы не показываете пример создания и использования 'TimerObject'. Ваш вопрос лучше, чем вчера, но вы должны действительно объяснить, как вы используете этот класс, и какова ваша фактическая цель пользователя - почему у вас много таймеров, почему бы нет 1 таймера и объектов, которые имеют «огонь до истек» или просто NSDate, когда они истекают? – Wain

+0

Извините, я не уверен, как показать использование объекта таймера без скриншота приложения. Я объясню как можно лучше. Пользователь нажимает на ссылку, которая сопоставляется с действием, которое уведомляет одинарный сигнал, чтобы запустить таймер на X минут, функция таймера запуска затем создает новую ячейку в таблице, отображающую рабочий таймер. Я использую NSTimer для уведомления persistTimer, чтобы сообщить tableView обновить ячейку с новым уменьшенным временем. Пользователь может запустить любое количество таймеров, и они могут активировать таймер любое количество раз, это ограничения. –

+0

Использование NSDate не позволит мне обновлять tableView каждую секунду. Кроме того, можете ли вы подробнее рассказать о том, почему 'var timer = NSTimer()' является табу? –

ответ

0

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

private var timer = NSTimer() 
    var isFirstTimer = false 


    public func timerAdded(newTimerObject: TimerObject){ 
     if(isFirstTimer){ 
      self.timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(persistTimers(_:)), userInfo: nil, repeats: true) 
     } 
     self.currentTimers.append(newTimerObject) 
     newTimerObject.isRunning = true 
     for delegate in delegates{ 
      delegate.startTimer(self.currentTimers[self.currentTimers.count-1]) 
     } 
    } 

    @objc public func persistTimers(timer: NSTimer){ 
     for i in 0..<self.currentTimers.count{ 
      if let currentTimer = currentTimers[safe: i]{ 
       if(currentTimer.isRunning){ 
        currentTimer.timeDuration -= 1 
        for delegate in delegates{ 
         delegate.timerStarted(i) 
        } 
       } 
      } 
     } 
    } 

Это в конечном счете, что я в конечном итоге изменить в моей одноплодной декларации и я в конечном итоге удаления

currentTimer.timeDuration -= 1 

строку из функции timerStarted в функцию persistTime ... Я понимаю, что моя реализация и стиль имеет много желаний, но это начало. Всего лишь 2 недели в программировании на iOS.

EDIT:

"[safe: ]" расширение я добавил для безопасного доступа индекс:

public extension CollectionType{ 
    subscript (safe index: Index) -> Generator.Element? { 
     return indices.contains(index) ? self[index] : nil 
    } 
} 
Смежные вопросы