我正在编写一个基本的音乐播放器应用,但在处理应用状态转换方面遇到了一些问题。
我使用Swift 3和MPMusicPlayerController.systemMusicPlayer()
目标是:
1)当用户点击主页按钮并且应用进入bg(工作)
时,保持音乐播放2)如果退出应用程序的用户停止播放器(myMP.stop())(有时工作,其他时间抛出错误)
我根据可能的操作使用print语句跟踪流程并得到了这个:
Flow 2是我所期望的,但是Flow 1会抛出错误 当应用程序关闭时 - 我希望"将终止"这里。
编辑:主要问题是当使用流程1退出应用程序时,"将终止"永远不会被调用 - 因此" myMP.stop()"永远不会被调用,播放器会在应用程序退出后继续播放。
如果您在应用处于活动状态时单击Home(流量1)或双倍(流量2),行为会有明显差异。
为什么我会从应该相同的操作中得到两个不同的回复?
编辑: 最重要的是,如果它永远不会到达"将终止"如何停止MediaPlayer for Flow 1? ?
编辑:
以下是一些复制问题的示例代码:
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()
}
}
答案 0 :(得分:31)
“因信号9而终止”消息仅表示您的应用程序被SIGKILL信号终止。操作系统会在您的应用程序被非自愿终止时发送该信号,无论是因为内存压力(或与此讨论无关的其他几个原因),还是用户通过双击主页按钮并将其轻扫而明确查杀您的应用程序。
在您的情况下,用户明确地终止您的应用程序,因此完全需要“因信号终止9”消息。如果您的应用程序是当前的前台应用程序,则会调用applicationWillTerminate方法,如上面的逻辑流程大纲(流程2)所示。如果您的应用程序不是当前的前台应用程序(流程1),那么如果您的应用程序处于挂起状态,则不会调用applicationWillTerminate
方法。这是预期的行为。还要注意“背景状态”和“暂停状态”之间的区别。 They are not the same thing
因此,如果我正确理解您,听起来问题是在您的应用程序被用户终止后,音频会继续播放(流程1)。这意味着您在处理MPMusicPlayerController
时出错了,因为它应该自动处理该状态转换。
确保为您的应用设置了正确的UIBackgroundMode。设置错误的后台模式可能会导致应用程序出现异常,因为操作系统仅在后台运行时允许某些操作,具体取决于您设置的背景模式。设置错误的模式(或尝试执行您设置的模式中明确禁止的操作)将导致您的应用被暂停或终止。
确保您已正确设置音频会话。
确保您正确回复music player notifications - 特别是,请确保您正确调用beginGeneratingPlaybackNotifications
和endGeneratingPlaybackNotifications
,并确保正确处理这些通知。检查您的通知处理程序,以确保您没有在那里做任何愚蠢的事情。在调用endGeneratingPlaybackNotifications
之前,请确保您的控制器不会超出范围或以其他方式发布。
如果你已经正确地完成了所有其他工作,那么MPMusicPlayerController
几乎可以管理自己,所以当你的应用程序转到后台时,你不应该做任何特别的事情来使它工作(除了设置正确的UIBackgroundMode
,当然)。作为最后的手段,开始评论代码,直到您的应用程序只是一个准确的“打开音频文件并播放它”应用程序,然后查看它是否正常退出。如果是这样,您可以逐个取消注释代码直到失败 - 然后您知道应用程序的哪个部分导致了问题,您可以从那里缩小它。
答案 1 :(得分:2)
我有三个后台任务。
<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为后台运行应用程序的操作系统分配的内存。
在我的情况下,我正在更新User的位置并连续执行用户的位置api到服务器。这耗费了大量的内存。由于这个原因,操作系统杀死了App。
我们收到此消息是由于操作系统内存压力并在后台杀死了应用程序。
我优化了代码,每当我们需要更新用户位置时,我们只将位置api解雇到服务器。
我还enable \ disable
标志allowsBackgroundLocationUpdates
if #available(iOS 9.0, *) {
coreLocationManager.allowsBackgroundLocationUpdates = false
}
根据我们的需要。
它运作良好。
答案 2 :(得分:0)
Fyi:如果您在“设置”应用中更改了诸如“相机使用情况”和“照片使用情况”之类的应用权限,则您的应用也会因该信号而崩溃(硬刷新)。