Quitting app causes error "Message from debugger: Terminated due to signal 9"
Asked Answered
L

4

46

I'm writing a basic music player app but having some problems when it comes to handling the app state transitions.

I'm using Swift 3 and MPMusicPlayerController.systemMusicPlayer()

The goal is this:

1) Keep music playing when user taps the Home button and app enters bg (works)

2) Stop the player ( myMP.stop() ) if the user the quits the app (works sometimes, throws error other times)

I traced the flows using print statements based on possible actions and got this:

enter image description here

Flow 2 is what I would expect, but Flow 1 throws an error when the app is closed - I would expect "will terminate" here.

EDIT: The main issue is that when exiting the app using Flow 1, "will terminate" is never called - therefore "myMP.stop()" is never called and the player continues to play after the app has exited.

There is a distinct difference in behavior if you click Home once (Flow 1) or double (Flow 2) while the app is active.

Why do I get two different responses from what should be the same actions?

EDIT: Most importantly, how do I stop the MediaPlayer for Flow 1 if it never gets to "will terminate" ?

EDIT:

Here is some sample code that replicates the issue:

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()
    }
}

Download the project here: www.NextCoInc.com/public/junkplayer.zip

Lemuel answered 19/2, 2017 at 19:32 Comment(3)
Can you upload all code again? and I try to fix it. thanksRailhead
@JosePoseS I fixed the link above - you should be able to download now. As I mentioned below in my comments to Jeff, changing to the applicationMusicPlayer fixes the primary issue but causes others...Lemuel
In my case, I got this message when I was running app on device from xcode and at the same time, I tried installing same app from appstore on my device.Olivier
L
56

The "terminated due to signal 9" message just means your app was terminated by a SIGKILL signal. The OS sends that signal whenever your app is terminated involuntarily, whether it's because of memory pressure (or several other reasons not relevant to this discussion), or the user explicitly killing your app by double tapping the Home button and swiping it away.

In your case, the user is explicitly killing your application, so the "Terminated due to signal 9" message is completely expected. If your application is the current foreground application, your applicationWillTerminate method will get called, as shown in your logic flow outline above (Flow 2). If your application is NOT the current foreground application (Flow 1), your applicationWillTerminate method will NOT get called if your application is in a suspended state. This is expected behavior. Also note the distinction between "background state" and "suspended state". They are not the same thing.

So if I'm understanding you correctly, it sounds like the problem is that the audio continues playing after your application is terminated by the user (Flow 1). That means you are doing something wrong in your handling of the MPMusicPlayerController, because it should handle that state transition automatically.

Make sure you've set the correct UIBackgroundMode for your app. Setting the wrong background mode can cause your application to misbehave because the OS only allows certain operations while in background, depending on what background mode you've set. Setting the wrong mode (or trying to do things that are explicitly disallowed in the mode you've set) will cause your app to be suspended or terminated.

Make sure you've set up your audio session correctly.

Make sure you are responding correctly to the music player notifications - in particular, make sure you're calling beginGeneratingPlaybackNotifications and endGeneratingPlaybackNotifications appropriately, and that you are handling those notifications correctly. Check your notification handlers to make sure you aren't doing anything silly in there. Make sure your controller doesn't go out of scope or otherwise get released before you've called endGeneratingPlaybackNotifications.

If you've done everything else correctly, an MPMusicPlayerController pretty much manages itself, so you shouldn't have to do anything special to make it work when your app goes to the background (aside from setting the correct UIBackgroundMode, of course). As a last resort, start commenting out code until your app is just a barebones "open-an-audio-file-and-play-it" application, and see if it exits properly then. If it does, you can start uncommenting code piece-by-piece until it fails - then you know what part of your app is causing the problem and you can narrow it down from there.

Lewandowski answered 1/5, 2017 at 19:47 Comment(14)
I've read through your post and links (Thanks) I've created the simplest version of the player possible and I still have the same issue. I've set it to be a background Audio app - no change. I've declared the instance of my MediaPlayer in various places - no change. How can I provide a copy of this project to you to see if you can resolve the issue?Lemuel
Post the section of code where you set up your MPMusicPlayerController object. Make sure you are managing this object on the main thread (see: developer.apple.com/reference/mediaplayer/… ).Lewandowski
Also, are you using an Application Music Player, or the System Music Player? According to the link in my previous comment, if you don't specify it when you create the object, you'll get the System music player - maybe that's why it doesn't stop playing when your application is terminated?Lewandowski
I'll post my code in a little while - However, I can tell you that I'm using the System Music Player - the reason is that I want it to continue playing while in the background - same as the Apple Music player. Otherwise, hitting Home (etc) will pause the player.Lemuel
OK, I think I've resolved it. I've been using the System Music Player mistakenly thinking it was necessary for background playing. After reading and testing, I've switched to the Application Player and set the background capabilities in info.plist and it seems to be working fine. Plus it exits/stops playing no matter how I quit the app. I'm going to run some more tests but I believe you led me to the correct solution - I'll be happy to award the points once my tests are done!Lemuel
After more testing I'm finding a problem. Even if I use the applicationMusicPlayer, if I also run the App Music app - without starting to play anything - and the quit it, it also stops my music player while also leaving it running! I thought the whole idea of the applicationMusicPlayer was to be completely separate? I am so confused now...Lemuel
Make sure you set an appropriate audio session category on your AVAudioSession - developer.apple.com/library/content/documentation/Audio/…Lewandowski
I've not seen that before - I'll check it now.Lemuel
And I'm not sure what you mean by "stops my music player while also leaving it running"...Lewandowski
You can try this with the sample I provided: Start the app, hit the button to start playing, hit home button. Open the Apple Music App, then dbl-click home and swipe/quit Apple Music app. The song will stop playing, but you can bring the sample app to the foreground. However, hitting the button does nothing anymore.Lemuel
That's what beginGeneratingPlaybackNotifications is for. Your app should get notified when playback stops because of some external event - you need to respond to that and reinitialize your MPAudioPlayerControllerLewandowski
I can't find anything that indicates that setting a category is used in conjunction with the MediaPlayer. It appears to be used with AVAudioSession which I am not using. As for notifications, I am using them in my app but they do not respond to the specific incident where quitting the Apple Music player causes my app to stop and become unresponsive.Lemuel
Your app has a default AVAudioSession. Access it with [AVAudioSession sharedInstance]. Then register to receive AVAudioSessionInterruptionNotification events.Lewandowski
Do you mean if I close the simulator it is expected to get this error even when there are no bugs or memory leaks?Carotenoid
B
7

Changes in Settings app for app permissions like Camera or Photo usage, can result in crash(hard refresh) with this signal.

You can find related behaviors in the link below:

Beneficence answered 13/12, 2019 at 11:33 Comment(3)
Why is this happening?Pauperize
I Thing Apple will a hard refresh if user change something, so that app can start from AppDelegate as e new start.Beneficence
that was my case, I was testing my photo application to know how to handle manual settings change and was getting this crash & error message sometimes, glad to know it's how the system itself handle my app, I will continue to test my application though, we know that the problem can lie between the chair and the computer screen lmaoJarvey
S
3

I was having three background task for the App.

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

Message from debugger: Terminated due to signal 9 This message comes when app is running into the background and it consumes more memory which beyond the allocated memory by the os of a iPhone for Background running apps.

In my case, I was updating the location of User and executing location api of the user to the server continuously. It was consuming lots of memory. Due to this reason, OS killed the App.

We got this message due to memory pressure on OS and killed the app in the background.

I optimised the code and whenever we need to update location of user then only we fired the location api to server. I also enable \ disable the flag allowsBackgroundLocationUpdates

if #available(iOS 9.0, *) {
   coreLocationManager.allowsBackgroundLocationUpdates = false
}

according to our need. it worked fine.

Sulfathiazole answered 10/8, 2017 at 12:39 Comment(1)
What does "it worked fine" mean? Does that mean the App stayed in memory and was no longer "Terminated due to signal 9" ?Cattleman
L
0

App get this message frequently when device's low battery mode is on. Hope this helps.

Leucite answered 14/4, 2023 at 6:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.