web-dev-qa-db-ja.com

アプリを終了すると、「デバッガーからのメッセージ:シグナル9により終了しました」というエラーが発生する

基本的な音楽プレーヤーアプリを書いていますが、アプリの状態遷移の処理に関していくつかの問題があります。

Swift 3とMPMusicPlayerController.systemMusicPlayer()を使用しています

目標は次のとおりです。

1)ユーザーが[ホーム]ボタンをタップし、アプリがbg(動作する)になったときに音楽を再生し続ける

2)ユーザーがアプリを終了した場合はプレーヤーを停止します(myMP.stop())

可能なアクションに基づいてprintステートメントを使用してフローをトレースし、これを取得しました:

enter image description here

Flow 2は私が期待するものですが、アプリを閉じたときにFlow 1がエラーをスローします-ここで「終了する」ことを期待します。

編集:主な問題は、Flow 1を使用してアプリを終了するときに「終了」が呼び出されないことです。したがって、「myMP.stop()」は呼び出されず、アプリが終了した後もプレーヤーが再生を続けます。

アプリがアクティブなときに[ホーム]を1回(フロー1)またはダブル(フロー2)をクリックすると、動作に明確な違いがあります。

同じと同じアクションから2つの異なる応答を受け取るのはなぜですか?

編集:最も重要なのは、フロー1のMediaPlayerが「終了しない」場合に停止するにはどうすればよいですか?

編集:

問題を再現するサンプルコードを次に示します。

AppDelegate.Swift

//
//  AppDelegate.Swift
//  Jumbo Player
//

import UIKit
//import MediaPlayer

//doesn't matter where this is declared - here or in ViewController - same results
//let myMP:MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer()

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
        print("applicationWillResignActive")
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        print("applicationDidEnterBackground")
    }

    func applicationDidReceiveMemoryWarning(_ application: UIApplication) {
        print("applicationDidReceiveMemoryWarning")
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        print("applicationWillEnterForeground")
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        print("applicationDidBecomeActive")
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        print("applicationWillTerminate")
        myMP.stop();
    }
}

ViewController.Swift

//
//  ViewController.Swift
//  junkplayer
//

import UIKit
import MediaPlayer

let myMP:MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer()

class ViewController: UIViewController {

    @IBOutlet weak var xxx: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let qrySongs = MPMediaQuery.songs()
        myMP.setQueue(with: qrySongs)

    }

    @IBAction func playbut(_ sender: UIButton) {
        myMP.play()
    }
}

ここからプロジェクトをダウンロードしてください: www.NextCoInc.com/public/junkplayer.Zip

24
wayneh

「シグナル9により終了しました」というメッセージは、SIGKILLシグナルによってアプリが終了したことを意味します。 OSは、メモリの圧迫(またはこの議論に関係のない他のいくつかの理由)が原因であろうと、ユーザーがホームボタンをダブルタップしてスワイプしてアプリを明示的に強制終了した場合でも、アプリが不意に終了するたびにその信号を送信します。

あなたの場合、ユーザーは明示的にアプリケーションを強制終了しているため、「シグナル9による終了」メッセージが完全に予想されます。アプリケーションが現在のフォアグラウンドアプリケーションである場合、上記のロジックフローの概要(フロー2)に示すように、 applicationWillTerminate メソッドが呼び出されます。アプリケーションが現在のフォアグラウンドアプリケーションでない場合(フロー1)、アプリケーションが一時停止状態の場合、applicationWillTerminateメソッドは呼び出されません。これは予想される動作です。 「バックグラウンド状態」と「サスペンド状態」の違いにも注意してください。 これらは同じものではありません

したがって、私があなたを正しく理解している場合、問題は、アプリケーションがユーザーによって終了された後もオーディオの再生が続くということです(フロー1)。つまり、MPMusicPlayerControllerの処理で何か間違ったことをしていることを意味します。これは、その状態遷移を自動的に処理する必要があるためです。

アプリに正しい IBackgroundMode を設定していることを確認してください。間違ったバックグラウンドモードを設定すると、設定したバックグラウンドモードによっては、OSがバックグラウンドで特定の操作のみを許可するため、アプリケーションが誤動作する可能性があります。間違ったモードを設定すると(または設定したモードで明示的に許可されていないことを行おうとすると)、アプリが中断または終了します。

オーディオセッションが正しく設定されていることを確認してください。

音楽プレーヤーの通知 に正しく応答していることを確認してください。特に、beginGeneratingPlaybackNotificationsおよびendGeneratingPlaybackNotificationsを適切に呼び出していること、およびそれらの通知を正しく処理していることを確認してください。通知ハンドラをチェックして、そこでおかしなことをしていないことを確認してください。 endGeneratingPlaybackNotificationsを呼び出す前に、コントローラーが範囲外になったり、解放されたりしないようにしてください。

他のすべてを正しく行った場合、MPMusicPlayerControllerがそれ自体を管理するので、アプリがバックグラウンドになったときに動作させるために特別なことをする必要はありません(正しいUIBackgroundMode、 もちろん)。最後の手段として、アプリが必要最低限​​の「オーディオファイルを開き、再生する」アプリケーションになるまでコードをコメントアウトし、適切に終了するかどうかを確認します。失敗した場合は、失敗するまでコードごとにコメント解除を開始できます。アプリのどの部分が問題を引き起こしているかを把握し、そこから絞り込むことができます。

32
Jeff Loughlin

アプリのバックグラウンドタスクが3つありました。

_<key>UIBackgroundModes</key>
<array>
    <string>bluetooth-central</string>
    <string>location</string>
    <string>remote-notification</string>
</array> 
_

_Message from debugger: Terminated due to signal 9_このメッセージは、アプリがバックグラウンドで実行されており、アプリをバックグラウンドで実行するためにiPhoneのOSによって割り当てられたメモリを超えるより多くのメモリを消費するときに表示されます。

私の場合、ユーザーのロケーションを更新し、ユーザーのロケーションAPIをサーバーに対して継続的に実行していました。多くのメモリを消費していました。このため、OSはアプリを強制終了しました。

OSのメモリ不足によりこのメッセージが表示され、バックグラウンドでアプリが終了しました。

コードを最適化し、ユーザーの場所を更新する必要があるときはいつでも、場所apiをサーバーに送信しました。私も_enable \ disable_フラグallowsBackgroundLocationUpdates

if #available(iOS 9.0, *) { coreLocationManager.allowsBackgroundLocationUpdates = false }必要に応じて。うまくいきました。

2
Anil Gupta