【问题标题】:Swift - Press Button (completion handler issue)Swift - 按下按钮(完成处理程序问题)
【发布时间】:2016-09-11 16:22:06
【问题描述】:

我希望用户按下一个按钮,它会更改背景颜色(变为黄色),播放 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)
}

【问题讨论】:

    标签: swift completionhandler


    【解决方案1】:

    要检测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)
    }
    

    (您需要在 ViewController 的声明标头中添加对 AVAudioPlayerDelegate 的一致性。)

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        这是其中一个比看上去更微妙的问题。我尝试在每个任务周围放置三个完成处理程序:将颜色更改为黄色,播放声音,将颜色更改回红色。代码在我 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 {
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2021-06-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多