Работа таймера в фоновом режиме

xcode
ios
swift

#1

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


#2
  1. Через некоторое время, приложение в бекграунде завершается.

  2. Создать бэкграунд таск

    let timer = NSTimer.scheduledTimerWithTimeInterval(N, target: self, selector: #selector(timerFunc(_:)), userInfo: nil, repeats: true)

    func timerFunc(timer: NSTimer) {
    //starts background task
    let backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler {}

    //stops background task
    if backgroundTask != UIBackgroundTaskInvalid {
    if UIApplication.sharedApplication().applicationState == .Active {
    UIApplication.sharedApplication().endBackgroundTask(backgroundTask!)
    backgroundTask = UIBackgroundTaskInvalid
    }
    }
    }

Это код swift 2.3, разберетесь?


#3

Исправите ,если ошибся?)

let timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(timerFunc), userInfo: nil, repeats: true)

func timerFunc(timer: Timer) {
        var backgroundTask = UIApplication.shared.beginBackgroundTask {}
        if backgroundTask != UIBackgroundTaskInvalid {
            if UIApplication.shared.applicationState == .active {
                UIApplication.shared.endBackgroundTask(backgroundTask)
                backgroundTask = UIBackgroundTaskInvalid

P.S. скомпилил. Вроде как изначально все пошло хорошо , но при перезупуске в программу вселился дьявол. Ищу проблему


#4

Все верно, только вы не добавили никакой функционал в таск.

И что этот дьявол делает?)


#5

При включении приложения ,начинается отсчет со скоростью звука ,а когда время заканчивается и подъест звуковой сигнал включаются все звуки одновременно )


#6

Код в студию, если можно (желательно чтобы там было все, что затрагивает таймер).


#7

import UIKit
import AVFoundation
import AudioToolbox

class ViewController: UIViewController {

@IBOutlet weak var softboiledBt: UIButton!

@IBOutlet weak var inapounchBt: UIButton!

@IBOutlet weak var hardboiledBt: UIButton!

let softboiledConst = 240
let inapounchConst = 360
let hardboiledConst = 450
/*let timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(timerFunc), userInfo: nil, repeats: true)*/

var selectedType = Array(repeating: false, count: 3)
var timery = Timer()
var isStarted = false
var counter: Int?

@IBAction func softboiledAction(_ sender: Any) {
    if !isStarted {
    selectedType[2] = false
    selectedType[1] = false
    selectedType[0] = true
    setHighLightingForButtons()
    refreshTimer()
    }
}

@IBAction func inapounchAction(_ sender: Any) {
    if !isStarted{
    selectedType[2] = false
    selectedType[1] = true
    selectedType[0] = false
    setHighLightingForButtons()
    refreshTimer()

}
}

@IBAction func hardboiledAction(_ sender: Any) {
    if !isStarted {
    selectedType[2] = true
    selectedType[1] = false
    selectedType[0] = false
    setHighLightingForButtons()
    refreshTimer()
    }
}

@IBOutlet weak var startbuttonoutlet: UIButton!



@IBAction func startbuttonAction(_ sender: Any) {
    if !isStarted {
        counter = getCurrentTimer()
        timery.invalidate()
        timery = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.timerAction), userInfo: nil, repeats: true)
    startbuttonoutlet.setImage(#imageLiteral(resourceName: "stop"), for: UIControlState())
        isStarted = true
        disableButton ()
        
    }else{
        isStarted = false
        timery.invalidate()
        refreshTimer()
        enableButton()
    setHighLightingForButtons()
        startbuttonoutlet.setImage(#imageLiteral(resourceName: "play-button"), for: UIControlState())
    }
}

@IBOutlet weak var timerLabel: UILabel!

func timerAction() {
    counter! -= 1
    if counter! < 0 {
        timerLabel.text = "Ready"
        AudioServicesPlaySystemSound(SystemSoundID(1073))
        AudioServicesPlaySystemSound(SystemSoundID(4095))
    }else {
    timerLabel.text = NSString (format: "%0.2d:%0.2d",counter!/60,counter!%60) as String
}
}

func refreshTimer() {
    counter = getCurrentTimer()
    timerLabel.text = NSString (format: "%0.2d:%0.2d",counter!/60,counter!%60) as String
    
}

func disableButton () {
    softboiledBt.isEnabled = false
    inapounchBt.isEnabled = false
    hardboiledBt.isEnabled = false

}
func enableButton () {
    softboiledBt.isEnabled = true
    inapounchBt.isEnabled = true
    hardboiledBt.isEnabled = true
    
}

/* func timerFunc(timer: Timer) {
var backgroundTask = UIApplication.shared.beginBackgroundTask {
//доделать
}

 }
    if backgroundTask != UIBackgroundTaskInvalid {
        if UIApplication.shared.applicationState == .active {
            UIApplication.shared.endBackgroundTask(backgroundTask)
            backgroundTask = UIBackgroundTaskInvalid
        }
    }
}*/
    



override func viewDidLoad() {
    super.viewDidLoad()
    softboiledBt.isHighlighted = true
    inapounchBt.isHighlighted = true
    selectedType[2] = true
    timerLabel.text = NSString(format: "%0.2d:%0.2d",hardboiledConst/60,hardboiledConst%60) as String 
}

func getCurrentTimer() -> Int {
    if selectedType [0] {
    return softboiledConst
}
    else if selectedType [1] {
        return inapounchConst
    } else{
        return hardboiledConst
    }
}

func setHighLightingForButtons() {
    if selectedType[0]{
        softboiledBt.isHighlighted = false
        inapounchBt.isHighlighted = true
        hardboiledBt.isHighlighted = true
        
    }else if selectedType[1]{
        softboiledBt.isHighlighted = true
        inapounchBt.isHighlighted = false
        hardboiledBt.isHighlighted = true
        
    }else if selectedType[2]{
        softboiledBt.isHighlighted = true
        inapounchBt.isHighlighted = true
        hardboiledBt.isHighlighted = false
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}

Без того ,что в комментариях работает ,вроде как ,корректно. Изначально подумал ,что налажал с секундами. Потом добавил функционал в таск ,но все вылетало после 10 секунд отсчета. Поэтому прокомментировал и дописал " доделать " (на будущее)

Сигнал один оставил еще


#8

Скорее всего приложение вело себя так потому, что вы не туда вписали функционал:

/// таймер должен быть instance variable, если повторяется и не намерены делать timer.invalidate() в том же методе, в котором ег создали
var timer: Timer!

func timerFunc(timer: Timer) {
    var backgroundTask = UIApplication.shared.beginBackgroundTask() /// кложур можно убрать, если вам не нужно обрабатывать expirationHandler
    /// здесь пишется функционал бэкграунд таска
    /// к примеру, выводить интервал таймера
    print(timer.timeInterval.binade)
    
    if backgroundTask != UIBackgroundTaskInvalid {
        if UIApplication.shared.applicationState == .active {
            UIApplication.shared.endBackgroundTask(backgroundTask)
            backgroundTask = UIBackgroundTaskInvalid
        }
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    softboiledBt.isHighlighted = true
    inapounchBt.isHighlighted = true
    selectedType[2] = true
    timerLabel.text = NSString(format: "%0.2d:%0.2d",hardboiledConst/60,hardboiledConst%60) as String
    /// измените интервал таймера на свое усмотрение
    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerFunc), userInfo: nil, repeats: true)
}