简体   繁体   中英

How can I play a sound on iOS?

I have built a random number generator, I want it to play a sound when the button is pressed. Xcode doesn't give me any errors and when I simulate my app it generates numbers no problem but there is no sound. I have my sound in a sound folder.

Here is my code.

import UIKit
import AVFoundation


class ViewController: UIViewController {

    var player: AVAudioPlayer!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBOutlet weak var operations: UIImageView!
    @IBOutlet weak var bottomRightNumber: UIImageView!
    @IBOutlet weak var bottomMiddleNumber: UIImageView!
    @IBOutlet weak var bottomLeftNumber: UIImageView!
    @IBOutlet weak var topRightNumber: UIImageView!
    @IBOutlet weak var topMiddleNumber: UIImageView!
    @IBOutlet weak var topLeftNumber: UIImageView!

    @IBAction func buttonPressed(_ sender: UIButton) {

        let numberArray = [#imageLiteral(resourceName: "RN1"), #imageLiteral(resourceName: "RN2"), #imageLiteral(resourceName: "RN3"), #imageLiteral(resourceName: "RN4"),#imageLiteral(resourceName: "RN5"), #imageLiteral(resourceName: "RN6"), #imageLiteral(resourceName: "RN7"), #imageLiteral(resourceName: "RN8"), #imageLiteral(resourceName: "RN9"), #imageLiteral(resourceName: "RN0")]

        bottomRightNumber.image = numberArray.randomElement()
        bottomLeftNumber.image = numberArray.randomElement()
        bottomMiddleNumber.image = numberArray.randomElement()
        topRightNumber.image = numberArray.randomElement()
        topMiddleNumber.image = numberArray.randomElement()
        topLeftNumber.image = numberArray.randomElement()

        let operationArray = [#imageLiteral(resourceName: "-"), #imageLiteral(resourceName: "+")]

        operations.image = operationArray.randomElement()

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

             do { /* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
                    player = try! AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue)
                player.play()

                }
            }
        }
}

Looks like you just copied and pasted someone else's code. But you pasted it into some other code, so the problem now is that your code that plays sound has ended up wrapped in a nested function declaration, inside your func buttonPressed code:

func playSound() {
    guard let url = Bundle.main.url(forResource: "A", withExtension: "wav") else { return }
    do { 
        player = try! AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue)
        player.play() // this is where sound _would_ play
    }
}

Nothing ever calls that function, so it never runs.

Just delete those two lines that wrap the code, and now the code can run as part of what buttonPressed does. I would also suggest removing the pointless do construct as well, so you will end up with this:

    guard let url = Bundle.main.url(forResource: "A", withExtension: "wav") else { return }
    player = try! AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue)
    player.play() // this is where sound _would_ play

Your sound still might not play, or you might crash, but at least the code will now actually run!


Having said all that, let me change the code a little more to demonstrate best practices:

    guard let url = Bundle.main.url(forResource: "A", withExtension: "wav") else {
        print("the URL was not valid") // tell yourself what went wrong
        return
    }
    do {
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue)
        player.play()
    } catch { print(error) } // tell yourself what went wrong

In that version, I've put the do construct back, but this time it actually does something useful.

you can do 2 things: 1. Take the function playSound() out of the buttonPressed action and call the playSound() function - because I see that you have not called the function to play the sound. 2. you can just take the audio code out of the function playSound() if you are eventually going to use it there itself.

Here is the sample class to play sounds,

import Foundation
import AudioToolbox
import AVKit

class SoundManager {

    static var objPlayer: AVAudioPlayer?
    class func playAppLaunchSound() {

        registerAndPlaySoundForFile(fileName: "AppLaunchSound", fileExtension: "mp3")
    }

    class func playEnterButtonSound() {

        registerAndPlaySoundForFile(fileName: "EnterButtonSound", fileExtension: "mp3")
    }

    private class func registerAndPlaySoundForFile(fileName: String, fileExtension: String, withVibration: Bool = true) {

        let bundle = Bundle.main
        guard let url = bundle.url(forResource: fileName, withExtension: fileExtension) else {
            return
        }
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
            try AVAudioSession.sharedInstance().setActive(true)
                        objPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
            guard let aPlayer = objPlayer else { return }
            aPlayer.play()

        } catch let error {
            print(error.localizedDescription)
        }
    }
}

registerAndPlaySoundForFile is the main method responsible to play sound! You can use it like SoundManager.playEnterButtonSound() . You can create multiple methods in this class like this.

If you want to play sounds in your iOS application, stop what you are doing. Throw away the manual on swifts built in audio services and use a framework.

AudioKit is an incredible powerful framework built by some very competent audio programmers. This library has a nice API, is well documented and is very powerful. They have plenty of example apps, including sample code to help get you started. If you just want to play a sound, you will be covered. If you wanted to build a granular synth, you will also be covered.

Especially if you are new to programming, usually someone has done the hard work for you. Don't reinvent the wheel!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM