I'm currently making an app for runners that beeps at strides per minute to keep an even stride. I want my app to be able to work in the background but whenever I close my phone or minimize the app it stops playing

I've tried using other methods like AudioServices and mixing types but they aren't working for me

import UIKit import AVFoundation

class ViewController: UIViewController {

// Array of sound values
private var soundArray = [1057, 1113, 1127, 1261]

// indicates whether the start button is pressed or not
var status: Bool = true

// timer variable
var timer: Timer?

// holds the value for the the timer interval
var stridesPerMinute: TimeInterval = 160
var sliderValue: Double = 160

var systemSoundID: SystemSoundID = 1016

let defaults = UserDefaults.standard

@IBOutlet weak var striderSlider: UISlider!
@IBOutlet weak var sliderLabel: UILabel!
@IBOutlet weak var soundStepper: UIStepper!

override func viewDidLoad() {
    // Do any additional setup after loading the view.
    soundStepper.wraps = true
    soundStepper.autorepeat = true
    soundStepper.minimumValue = 0
    soundStepper.maximumValue = 3

    // if the user bool is true, then this is the first time opening the app
    if defaults.bool(forKey: "firstRun") {
        defaults.set(false, forKey: "firstRun")
        systemSoundID = UInt32(soundArray[0])
    } else{
        // if the user bool is false, then the app has been opened more than once and userDefault data should be used in place of placeholder values

        //restores the saved sound of the user
        let soundNum = defaults.double(forKey: "soundValue")
        systemSoundID = UInt32(soundArray[Int(soundNum)])

        // restores the saved stride per minute value of the user
        stridesPerMinute = defaults.double(forKey: "strideValue")

        // restores the saved slider value of the user
        sliderValue = defaults.double(forKey: "sliderValue")
        sliderLabel.text = "\(Int(sliderValue))"


@IBAction func sliderValueChanged(_ sender: UISlider) {
    // update slider value and text
    sliderValue = Double(sender.value)
    sliderLabel.text = "\(Int(sliderValue))"

    // reset the timer with the new input received from slider

    if !status {

    // update the userDefaults with the new slider value
    defaults.set(sliderValue, forKey: "sliderValue")

@IBAction func toggleStartStop(_ sender: UIButton) {
    //If the button status is true use stop functions, relabel button
    if status {
        // make the button into PAUSE image
        sender.setImage(UIImage(named: "btn_pause"), for: .normal)
        status = false
    } else{

        //make the button into START image
        sender.setImage(UIImage(named: "btn_play"), for: .normal)
        status = true

@IBAction func soundChanger(_ sender: UIStepper) {
    // update the current sound by stepping either up or down in the array
    systemSoundID = UInt32(soundArray[Int(sender.value)])
    defaults.set(sender.value, forKey: "soundValue")

    // if the timer isn't in use, play the sound so the user knows which sound is currently selected
    if status {

func start(){

    // calculate and save the current user strides per minute
    stridesPerMinute = TimeInterval(60 / sliderValue)
    defaults.set(stridesPerMinute, forKey: "strideValue")

    // initialize a timer using the strides per minute value and call the playSound function to create a metronome

    timer = Timer.scheduledTimer(timeInterval: TimeInterval(stridesPerMinute), target: self, selector: #selector(playSound), userInfo: nil, repeats: true)

func stop(){
    // stops the timer runtime and removes it from its run loop

@objc func playSound() {
    // plays the desired sound from system settings, set by the user using a stepper



it currently only runs the timer when the app is open, and only when the ringer is on. Is there anything I could do to change it so I can have it make sounds when its closed or in the background

Related posts

Recent Viewed