Coding help requested

I am relatively new to coding and put together this countdown timer based on code available in various public forums. This countdown timer for my iPhone puts a timer on my screen, allows me to select the time counted down in minutes and seconds, then to start the timer and, if so desired, reset it.While such timers are readily available, I wanted to try and build one myself and learn swift in the process. The program builds and runs fine. However the latter section is intended to play a chime when the countdown timer reaches the 1/2 way point and then when it finishes. This is not working and I'm at a loss to get it to do so. I would appreciate it if someone would modify my code to make this work. Also, I don't know how to compile the program so that I can move it off my MacBook and onto my iPad and would appreciate guidance on that. The code follows: Thank you

// // Content-ViewModel.swift // Countdown Timer // //
//

import Foundation import AVFoundation

extension ContentView { //contains the initial user interface final class ViewModel: ObservableObject { @Published var isActive = false @Published var showingAlert = false @Published var time: String = "1:00" @Published var minutes: Float = 1.0 {

        didSet {
            self.time = "\(Int(minutes)):00"
            
        }
        
    }
    
    private var initialTime = 0     // sets the var initialTime to 0
    private  var endDate = Date()   // sets endDate to the current date
    
    //  this next func starts timer in minutes
    
    func start(minutes: Float) {   //  this starts timer in minutes
        self.initialTime = Int(minutes)
        self.endDate = Date()
        self.isActive = true     // true means the timer is active
        self.endDate = Calendar.current.date(byAdding: .minute, value: Int(minutes), to: endDate)!
    }
    
    // this next func updates the var minutes to original time
    
    func reset() {
        self.minutes = Float(initialTime)
        
        self.isActive = false
        self.time = "\(Int(minutes)):00"
    }
    
    // this next func calculates the elapsed time
    
    func updateCountDown() {
        guard isActive else { return }
        let now = Date()
        let diff = endDate.timeIntervalSince1970 - now.timeIntervalSince1970
        
        if diff <= 0 {  // means timer is at zero
            self.isActive = false
            self.time = "0:00"
            self.showingAlert = true
            return
            
            // coud add code here to signify time is up
        }
        // This next code allows us to grab minutes and seconds from the calendar
        let date = Date(timeIntervalSince1970: diff)
        let calendar = Calendar.current
        let minutes = calendar.component(.minute, from: date)
        let seconds = calendar.component(.second, from: date)
        
        self.minutes = Float(minutes)
        self.time = String(format: "%d:%02d", minutes, seconds) // this creates the 2 digit display of                                                              minutes and seconds as a string
        
        
       let halftime = minutes/2  // This shoud create a float variable equal to 1/2 run time
       let chimesSoundEffect = "Chimes-sound-effect.mp3"
        
       
        
        
        
        
  /*   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  */
                    
   var player: AVAudioPlayer?

   func playSound() {
       guard let url = Bundle.main.url(forResource: "sound", withExtension: "mp3") else { return }

       do {
           try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
           try AVAudioSession.sharedInstance().setActive(true)

           player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)

           guard let player = player else { return }
           
           player.play()

       }
       catch let error {
           print(error.localizedDescription)
       }
 
       let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
       
           /* why doesn't the sound play when the halftime reached minutes/2 or when time reaches 0 */
           
           if minutes == halftime {
            
               playSound()
               
               
               if minutes == 0 {
                   timer.invalidate()
                   playSound()
               }
               
           }
           
       }
           
       
       
   }
                    
                }
            }
            
        }
        
    

Replies

You specify the sound to play:

let chimesSoundEffect = "Chimes-sound-effect.mp3"

But then use a different one when loading the sound file:

guard let url = Bundle.main.url(forResource: "sound", withExtension: "mp3") else { return }

Should you use the one you specify in the variable (without the extensions since you provide it as withExtension parameter):

let chimesSoundEffect = "Chimes-sound-effect"
...
guard let url = Bundle.main.url(forResource: chimesSoundEffect, withExtension: "mp3") else { return }

Hard to say otherwise what could be the issue. If you'd like someone else to test and help out getting this to work, I'd say put this in GitHub as a public repository and let others contribute there. It would be lots of work for others to create an empty project to test out this code of yours there, including putting mp3 files in resources of the app. And if the issue is elsewhere in your project (like where the mp3 file is located), seeing this code only may not be enough to solve your issues.

  • I tried your idea but the mp3 still failed to play. I then created a public GitHub repository called “hbenditsky” and included all the code for the project named Countdown Timer, along with the mp3 file. The program runs and produces a countdown timer on my iPhone. The timer has a Slider which allows me to select a duration up to 60 minutes. I intend it to play the mp3 file at the mid point and then when the counter times out. I would appreciate any further help you can provide. Thanks

Add a Comment

Found your GitHub repo, unfortunately it did not contain the Xcode project file so couldn't get it up and running.

I would change this:

guard let url = Bundle.main.url(forResource: chimesSoundEffect, withExtension: "mp3") else { return }

to this:

guard let url = Bundle.main.url(forResource: chimesSoundEffect, withExtension: "mp3") else {
   print("No sound file found")
   return
}

To see if the file is actually found. Furthermore, I would change this:

let chimesSoundEffect = "Chimes-sound-effect.mp3"

to this:

let chimesSoundEffect = "Chimes-sound-effect"

Since you already have the withExtension in the Bundle.url call.

Also I would check if you have included the mp3 file in the Target membership of the app:

1. First in Xcode, select the mp3 file in the left hand side where the project files are. 2. Check from the Inspector (View > Inspectors > File) and then see from the Target Membership section if there is a check in the checkbox for the app target.

If not, the mp3 file is not included in the target binary and cannot be found.

Just remembered I've done something similar before. Here's the code:

         if let soundURL = Bundle.main.url(forResource: soundFile, withExtension: "m4a") {
            do {
               if debug { print("Playing now.") }
               alarmSound = try AVAudioPlayer(contentsOf: soundURL)
               if let player = alarmSound {
                  player.prepareToPlay()
                  player.play()
               } else {
                  if debug { print("Could not load alarm sound file!") }
               }
            } catch {
               if debug { print(error.localizedDescription) }
            }
         }

In general, I would also add print statements (or logging using Logger) to all the places things went the wrong way. That way you can more easily identify what is the actual issue.