创建观察者以检查MediaPlayer播放状态是否已暂停

时间:2018-09-20 18:38:15

标签: swift

我有一个音乐应用程序,并且我想确定在关闭该应用程序时是否已暂停播放(由于诸如电话之类的事件或将AirPods拿出耳朵等)

我的第一种方法是在viewWillAppear内运行已检查的功能

if mediaPlayer.playbackState == .paused {
    ...
}

如果已暂停,则更新了播放/暂停按钮图像。但是,此操作不起作用,即使已暂停,“播放/暂停”按钮仍会显示“播放”。

接下来,我尝试将观察者添加到viewDidLoad

NotificationCenter.default.addObserver(self, selector: #selector(self.wasSongInterupted(_:)), name: UIApplication.didBecomeActiveNotification, object: self.mediaPlayer)

我打电话的self.wasSongInterupted

@objc func wasSongInterupted(_ notification: Notification) {
    DispatchQueue.main.async {
        if self.mediaPlayer.playbackState == .paused {
            print("paused")
            self.isPlaying = false
            self.playPauseSongButton.isSelected = self.isPlaying
        } else if self.mediaPlayer.playbackState == .playing {
            self.isPlaying = true
            self.playPauseSongButton.isSelected = self.isPlaying
        }
    }
}

但是,我仍然遇到同样的问题。

重新打开应用程序时,确定音乐播放器是播放还是暂停的最佳方法是什么?

编辑1:我根据注释编辑了代码。

wasSongInterrupted没有被调用,通过断点和错误,我发现代码基本上是不需要的。我将代码更改为

func wasSongInterrupted() {
  DispatchQueue.main.async {
    if self.mediaPlayer.playbackState == .interrupted {
      var isPlaying: Bool { return self.mediaPlayer.playbackState == .playing }
    print("Playback state is \(self.mediaPlayer.playbackState.rawValue), self.isPlaying Bool is \(self.isPlaying)")
      self.playPauseSongButton.setImage(UIImage(named: "playIconLight"), for: .normal)
      //self.playPauseSongButton.isSelected = self.isPlaying
    }
  }
}

在我的AppDelegate的applicationDidBecomeActive中,

let mediaPlayerVC = MediaPlayerViewController()
mediaPlayerVC.wasSongInterupted()

现在代码可以运行了,但是我遇到了一个问题。

如果我运行以下代码:

if self.mediaPlayer.playbackState == .interrupted {
  print("interrupted \(self.isPlaying)")
}

,然后拨打电话并返回到应用程序,它将到达断点。它将打印出中断以及false self.isPlaying

的Bool值

但是,如果我尝试通过

更新用户界面
self.playPauseSongButton.isSelected = self.isPlaying

或通过

self.playPauseSongButton.setImage(UIImage(named: "playIconLight.png"), for: .normal)

我收到一条错误消息Thread 1: EXC_BREAKPOINT (code=1, subcode=0x104af9258)

1 个答案:

答案 0 :(得分:1)

您尝试从viewWillAppear更新播放器用户界面。来自Apple Documentation

  

viewWillAppear(_:)

     

在将视图控制器的视图添加到视图层次结构之前,以及配置用于显示该视图的任何动画之前,将调用此方法。

因此,如果您的应用是suspended,并且再次变成active,则不会调用此方法,因为您的UIViewController已经在Navigations Stack

如果您想抓住应用程序从active状态变为suspended的时刻,则需要使用AppDelegate。来自Apple Documentation

  

applicationDidBecomeActive(_:)

     

调用此方法是为了让您的应用知道它已从非活动状态变为活动状态。发生这种情况的原因是您的应用是由用户或系统启动的。

因此,您需要在AppDelegate处使用此方法来处理应用程序的运行并更新您的界面。

更新

您在说自己正在使用的AppDelegate方法的内部

let mediaPlayerVC = MediaPlayerViewController()
mediaPlayerVC.wasSongInterupted()

那是错误的,因为您正在创建新的视图控制器。您需要做的是从导航堆栈访问您的现有视图控制器并进行更新。

可能的解决方案之一是使用NotificationCenter发送通知。您当然应该订阅该事件的控制器。

首先,您需要创建一个通知名称

extension Notification.Name {
    static let appBecameActive = Notification.Name(rawValue: "appBecameActive")
}

然后在您的AppDelegate中添加以下代码,以在应用程序激活时发布通知

func applicationDidBecomeActive(_ application: UIApplication) {
    NotificationCenter.default.post(name: .appBecameActive, object: nil)
}

最后在您的视图控制器中添加以订阅通知

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self,
                                           selector: #selector(wakeUp),
                                           name: .appBecameActive,
                                           object: nil)
    ...
}

@objc func wakeUp() {
    // Update your UI from here
}

希望它对您有帮助。