開発メモ

開発関係のメモをいろいろと。たぶん。

isPlayingがおかしくなる問題に対応

動作を確認した環境

環境 情報
Xcode 6.3.2 (6D2105)
iOS 8.3
Swift 1.2
Date 2015/6/7

isPlayingがおかしくなる問題に対応

問題の詳しい内容はこちらを参照。

MPMusicPlayerController::playbackStateがおかしくなる問題 - 開発メモ
http://seeku.hateblo.jp/entry/2014/07/07/164821

簡単に言うと、MPMusicPlayerController::playbackStateは信頼出来ないということ。では、どうするべきか?

class SK4MusicPlayerAdmin: NSObject {

    ※関係ない部分は省略

    /// 再生中か?
    func isPlaying() -> Bool {

        // player.playbackStateは信頼出来ないので、
        // AVAudioSessionで再生状況を調べる
        let av = AVAudioSession.sharedInstance()
        return av.otherAudioPlaying
    }

}

こんな感じにしてみた。つまり、player.playbackStateはバッサリあきらめて、AVAudioSessionのレベルでオーディオが再生されているかどうかをチェックするようにしてみた。

ただし、この形に修正すると、今度はMPMusicPlayerControllerPlaybackStateDidChangeNotificationで問題が起きる。

通知が来た時点で、AVAudioSessionのレベルに変更が反映されてないという・・・ さり気なく、これも、Appleの実装ミスのような気がしないでもないんだけど。

仕方がないので通知を受けた時点で、その後の更新処理を遅らせて実行するように修正。

class SK4MusicPlayerAdmin: NSObject {

    func playbackStateChanged(notify: NSNotification) {

        // 通知の直後はAVAudioSessionで再生状況が取れないので、
        // 少し遅らせてチェックする
        let time = dispatch_time(DISPATCH_TIME_NOW, Int64(NSEC_PER_SEC / 10))
        let queue = dispatch_get_main_queue()

        dispatch_after(time, queue) { [weak self] in
            self?.onPlaybackStateChanged()
        }
    }

    ※関係ない部分は省略

}

単純に、GCDを使って遅延実行しているだけ。無駄に[weak self]を指定してあるのは、単なる個人的な趣味。

ミュージックプレイヤーであれば、一定の間隔でタイマーを回して何か処理するような実装もよくあるだろうし、そうであれば、そっちで毎回ステータスをチェックするようにすれば、こんな面倒な処理はやらなくて済む。

というか、Apple標準のミュージックアプリがその形になってるから、この部分のバグを直す気にならないんだろうな・・・

ソースコード

最終的なソースコードはこちら。

See_Ku / MusicPlayerTips — Bitbucket
https://bitbucket.org/See_Ku/musicplayertips

https://itunes.apple.com/jp/app/46-minute-shuffle/id991599315?mt=8&uo=4&at=10l8JW&ct=hatenablog