Swift - 按下按钮(完成处理程序问题)

时间:2016-09-11 16:22:06

标签: swift completionhandler

我希望用户按下按钮,它会改变背景颜色(变为黄色),播放WAV,并且在WAV完成后,按钮将恢复为原始颜色(变为红色)。所以在声音周围有一个完成处理程序。尝试了以下代码的各种组合,但是WAV播放并且按钮似乎没有改变颜色。

这是错误的做法还是我做错了什么?我不想让完成处理程序围绕颜色变化,因为我认为这样做有点过分。

非常感谢。

typealias CompletionHandler = (success:Bool) -> Void

@IBAction func fireButton(sender: AnyObject) {
    playLaser( { (success)-> Void in
        if success {
            self.shots -= 1
            self.labelShotsLeft.text = String(self.shots)
        } else {

        }
    })
}

 func playLaser(completionHandler: CompletionHandler) {
     fireButton.layer.backgroundColor = UIColor.yellowColor().CGColor
     let url = NSBundle.mainBundle().URLForResource("laser", withExtension: "wav")!
    do {
        player = try AVAudioPlayer(contentsOfURL: url)
        guard let player = player else { return }
        player.prepareToPlay()
        player.play()
        } catch let error as NSError {
            print(error.description)
    }
    self.fireButton.layer.backgroundColor = UIColor.redColor().CGColor
    completionHandler(success: true)
}

3 个答案:

答案 0 :(得分:2)

要检测AVAudioPlayer完成播放,您需要使用AVAudioPlayerDelegate

你可能需要写这样的东西:

func playLaser(completionHandler: CompletionHandler) {
    fireButton.layer.backgroundColor = UIColor.yellowColor().CGColor
    let url = NSBundle.mainBundle().URLForResource("laser", withExtension: "wav")!
    do {
        player = try AVAudioPlayer(contentsOfURL: url)
        guard let player = player else { return }
        player.delegate = self //<- Sorry, this was missing in my first post
        player.play()
    } catch let error as NSError {
        print(error.description)
    }
    audioPlayerCompletionHandler = completionHandler
}

var audioPlayerCompletionHandler: CompletionHandler?
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
    self.fireButton.layer.backgroundColor = UIColor.redColor().CGColor
    audioPlayerCompletionHandler?(success: true)
}

(您需要将AVAudioPlayerDelegate的一致性添加到ViewController的声明标题中。)

答案 1 :(得分:1)

代码不会因为你说play.play()而神奇地暂停和等待 - 这太可怕了!因此,您所谓的完成处理程序根本不是完成处理程序。它会立即运行 - 也就是说,只要你开始播放。您的代码不会获取有关音频播放器何时完成播放

的信息。

为此,您需要配置一个委托并接收音频播放器完成播放时发出的delegate message

答案 2 :(得分:0)

这是一个比眼睛更微妙的问题之一。我尝试在每个任务周围放置三个完成处理程序:将颜色更改为黄色,播放声音,将颜色更改为红色。代码正在以正确的顺序执行,因为我在NSLogged它,但由于屏幕更新控件,按钮从未改变颜色。以下是我希望其他读者可能会觉得有用的代码:

Swift 2.0

@IBAction func fireButton(sender: AnyObject) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        dispatch_sync(dispatch_get_main_queue()) {
            self.fireButton.layer.backgroundColor = UIColor.yellowColor().CGColor
        }
        self.playLaser( { (success)-> Void in
            if success {
                self.shots -= 1
            } else {
            }
        })
        dispatch_sync(dispatch_get_main_queue()) {
            self.labelShotsLeft.text = String(self.shots)
            self.fireButton.layer.backgroundColor = UIColor.redColor().CGColor
        }
    }
}

func playLaser(completion: (success: Bool) -> ()) {
    let url = NSBundle.mainBundle().URLForResource("laser", withExtension: "wav")!
    do {
        player = try AVAudioPlayer(contentsOfURL: url)
        guard let player = player else { return }
        player.play()
        completion(success: true)
        } catch let error as NSError {
        completion(success: false)
    }
}

Swift 3.0

@IBAction func fireButton(_ sender: AnyObject) {
    let fireQueue = DispatchQueue(label: "queueFirebutton")
    fireQueue.async {
        DispatchQueue.main.sync {
            self.fireButtonDisabled()
        }
        DispatchQueue.main.sync {
            self.playLaser()
            self.shots -= 1
            if self.shots <= 0 {
                self.shots = 0
            }
        }
        DispatchQueue.main.sync {
            if self.shots < 0 { self.shots = 0}
            self.labelShotsLeft.text = String(self.shots)
            sleep(1)
            self.fireButtonEnabled()
        }
    }
}

func playLaser() {
    let url = Bundle.main.url(forResource: "laser", withExtension: "wav")!
    do {
        player = try AVAudioPlayer(contentsOf: url)
        guard let player = player else { return }
        player.play()
    } catch {
    }
}