Swift: 多个函数同时工作

Swift: multiple functions working at the same time

在我的应用程序中,我有 2 个 UIButtons,每个按钮播放 2 种声音(播放一种声音,暂停,播放另一种声音),每次按下时 UIButtons 图像都会改变,我的应用程序也有一些 tabs.the 问题是,当我按下 UIButton(播放和完成声音大约需要 4 秒)时,我无法按下另一个按钮,甚至无法在选项卡之间切换,应用程序会冻结,直到 UIbutton 的操作完成与,然后我可以按其他按钮或切换标签。 这是我的代码:

import UIKit
import AVFoundation
import CoreData


class FirstViewController: UIViewController {

var player:AVAudioPlayer = AVAudioPlayer()

var player2:AVAudioPlayer = AVAudioPlayer()


@IBAction func play(_ sender: Any) {

    player.play()
    sleep(1)
    player2.play()
}

@IBAction func play2(_ sender: Any) {
    player.play()
    sleep(1)
    player2.play()  
}


@IBOutlet weak var play: UIButton!
@IBOutlet weak var play2: UIButton!

var buttonActive = false

@IBAction func pPressed(_ sender: Any) {
    if buttonActive {
        play.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
    } else {
        play.setBackgroundImage(UIImage(named: "Switch-Icon-40"), for: .normal)
    }
    buttonActive = !buttonActive
}

@IBAction func p2Pressed(_ sender: Any) {
    if buttonActive {
        play2.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
    } else {
        play2.setBackgroundImage(UIImage(named: "Switch-Icon-40"), for: .normal)
    }
    buttonActive = !buttonActive
}

override func viewDidLoad() {
    super.viewDidLoad()
    play.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
    play2.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)

do

    {

        let audioPath = Bundle.main.path(forResource: "DTMF-1", ofType: "mp3")
        try player = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)

        let audioPath2 = Bundle.main.path(forResource: "DTMF-2", ofType: "mp3")
        try player2 = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath2!) as URL)

 }

有什么方法可以让我的应用程序更快?

实现做某事、暂停和做其他事的一种著名方法是使用Timer.

以下代码还包括:

  • 如何正确实例化AVAudioPlayer
  • 如何使工作无效Timer
  • 如何stop AVAudioPlayer 何时可以重用
  • 如何在转换时停止播放

请尝试:

class FirstViewController: UIViewController {

    var player: AVAudioPlayer? //### You should not instantiate unused objects

    var player2: AVAudioPlayer?

    var secondSoundTimer: Timer?

    private func startPlaying() {
        stopPlaying()

        player?.play()
        //### Using `Timer` is one way to achieve pause-like thing.
        //### If you need to target older iOSs than 10.0, you need to modify this part.
        secondSoundTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) {timer in
            self.player2?.play()
            self.secondSoundTimer?.invalidate()
            self.secondSoundTimer = nil
        }
    }

    private func stopPlaying() {
        secondSoundTimer?.invalidate()
        secondSoundTimer = nil
        if let player = player, player.isPlaying {
            //### Stop playing (keeping internal `prepared` state) and rewind to the first place.
            player.pause()
            player.currentTime = 0
        }
        if let player2 = player2, player2.isPlaying {
            player2.pause()
            player2.currentTime = 0
        }
    }

    @IBOutlet weak var play: UIButton!
    @IBOutlet weak var play2: UIButton!

    var buttonActive = false

    @IBAction func pPressed(_ sender: Any) {
        startPlaying()
        if buttonActive {
            play.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
        } else {
            play.setBackgroundImage(UIImage(named: "Switch-Icon-40"), for: .normal)
        }
        buttonActive = !buttonActive
    }

    //### Don't you need `button2Active`?

    @IBAction func p2Pressed(_ sender: Any) {
        startPlaying()
        if buttonActive {
            play2.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
        } else {
            play2.setBackgroundImage(UIImage(named: "Switch-Icon-40"), for: .normal)
        }
        buttonActive = !buttonActive
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        play.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
        play2.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)

        do {
            //### You can get URL directly from Bundle
            //### It's better to apply forced-unwrapping as soon as possible, if you need it eventually.
            let audioURL = Bundle.main.url(forResource: "DTMF-1", withExtension: "mp3")!
            player = try AVAudioPlayer(contentsOf: audioURL)
            //### `prepareToPlay()` improves response for the first play.
            player?.prepareToPlay()

            let audioURL2 = Bundle.main.url(forResource: "DTMF-2", withExtension: "mp3")!
            player2 = try AVAudioPlayer(contentsOf: audioURL2)
            player2?.prepareToPlay()
        } catch {
            print(error)
            //... or any other things you need...
        }

        //...
    }

    //### Stop playing on transition to other ViewConrollers.
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        stopPlaying()
    }
}