我正在编写一个 iPhone 应用程序,由于某些用户操作,我需要强制它退出。清理应用程序分配的内存后,调用终止应用程序的适当方法是什么?
24 回答
在 iPhone 上没有退出应用程序的概念。应该导致应用退出的唯一操作是触摸手机上的主页按钮,这不是开发人员可以访问的。
根据 Apple 的说法,您的应用程序不应自行终止。由于用户没有点击 Home 按钮,因此任何返回到 Home 屏幕的操作都会给用户留下您的应用程序崩溃的印象。这是令人困惑的非标准行为,应该避免。
你试过exit(0)
吗?
或者,[[NSThread mainThread] exit]
虽然我没有尝试过它似乎是更合适的解决方案。
exit(0) 向用户显示为崩溃,因此向用户显示确认消息。确认暂停后(以编程方式按下主页按钮)并等待 2 秒,而应用程序正在以动画形式进入后台,然后退出用户视图
-(IBAction)doExit
{
//show confirmation message to user
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Confirmation"
message:@"Do you want to exit?"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"OK", nil];
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != 0) // 0 == the cancel button
{
//home button press programmatically
UIApplication *app = [UIApplication sharedApplication];
[app performSelector:@selector(suspend)];
//wait 2 seconds while app is going background
[NSThread sleepForTimeInterval:2.0];
//exit app when app is in background
exit(0);
}
}
在此处查看问答:https ://developer.apple.com/library/content/qa/qa1561/_index.html
问:如何以编程方式退出我的 iOS 应用程序?
没有提供用于优雅终止 iOS 应用程序的 API。
在 iOS 中,用户按下 Home 按钮来关闭应用程序。如果您的应用程序出现无法提供其预期功能的情况,推荐的方法是向用户显示警报,指出问题的性质以及用户可能采取的措施——打开 WiFi、启用定位服务等。允许用户自行决定终止应用程序。
警告:不要调用该
exit
函数。调用的应用程序exit
将在用户看来已经崩溃,而不是执行正常终止并动画返回主屏幕。此外,可能不会保存数据,因为如果您调用 exit,将不会调用
-applicationWillTerminate:
类似的方法。UIApplicationDelegate
如果在开发或测试期间需要终止您的应用程序,建议使用该
abort
函数或assert
宏
它并不是真正的退出程序的方法,而是一种迫使人们退出的方法。
UIAlertView *anAlert = [[UIAlertView alloc] initWithTitle:@"Hit Home Button to Exit" message:@"Tell em why they're quiting" delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
[anAlert show];
转到您的 info.plist 并检查“应用程序不在后台运行”键。这一次,当用户单击主页按钮时,应用程序完全退出。
将UIApplicationExitsOnSuspend
属性添加application-info.plist
到true
.
经过一些测试,我可以说以下内容:
- 使用私有接口:
[UIApplication sharedApplication]
会导致应用程序看起来像崩溃了,但它会- (void)applicationWillTerminate:(UIApplication *)application
在这样做之前调用; - using
exit(0);
也会终止应用程序,但它看起来“正常”(跳板的图标看起来像预期的那样,具有缩小效果),但它不会调用- (void)applicationWillTerminate:(UIApplication *)application
委托方法。
我的建议:
- 手动调用
- (void)applicationWillTerminate:(UIApplication *)application
委托。 - 打电话
exit(0);
。
您的 ApplicationDelegate 会收到用户有意退出的通知:
- (void)applicationWillResignActive:(UIApplication *)application {
当我收到此通知时,我只是打电话
exit(0);
哪个可以完成所有工作。最好的事情是,用户打算退出,这就是为什么在那里调用它应该不是问题的原因。
在我的音频应用程序上,当人们在音乐仍在播放时同步他们的设备后,有必要退出应用程序。同步完成后,我会立即收到通知。但在那之后立即退出应用程序实际上看起来就像一个崩溃。
因此,我设置了一个标志,以便在下一个后台操作时真正退出应用程序。同步后刷新应用程序是可以的。
我的应用程序最近被拒绝,因为我使用了一种未记录的方法。字面上地:
“不幸的是,它无法添加到 App Store,因为它使用的是私有 API。禁止使用非公共 API,如 iPhone 开发人员程序许可协议第 3.3.1 节所述:
“3.3.1 应用程序只能以 Apple 规定的方式使用文档化 API,不得使用或调用任何私有 API。”
您的应用程序中包含的非公共 API 是 terminateWithSuccess"
苹果说:
“警告:不要调用退出函数。调用退出的应用程序将在用户看来已经崩溃,而不是执行正常终止并动画返回主屏幕。”
我认为这是一个糟糕的假设。如果用户点击退出按钮并出现一条消息,例如:“应用程序现在将退出。”,它似乎没有崩溃。Apple 应该提供一种有效的方式来退出应用程序(而不是 exit(0))。
您不应直接调用该函数exit(0)
,因为它会立即退出应用程序,并且看起来您的应用程序已崩溃。因此最好向用户显示确认警报并让他们自己执行此操作。
斯威夫特 4.2
func askForQuit(_ completion:@escaping (_ canQuit: Bool) -> Void) {
let alert = UIAlertController(title: "Confirmation!", message: "Do you want to quit the application", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
completion(true)
}))
alert.addAction(UIAlertAction(title: "No", style: UIAlertAction.Style.cancel, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
completion(false)
}))
self.present(alert, animated: true, completion: nil)
}
/// Will quit the application with animation
func quit() {
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
/// Sleep for a while to let the app goes in background
sleep(2)
exit(0)
}
用法:
self.askForQuit { (canQuit) in
if canQuit {
self.quit()
}
}
这已经得到了一个很好的答案,但决定扩大一点:
如果不仔细阅读 Apple 的 iOS 人机界面指南,您的应用程序将无法被 AppStore 接受。(他们保留拒绝您对他们做任何事情的权利)“不要以编程方式退出”部分http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices。 html 是在这种情况下您应该如何处理的确切指南。
如果您在 Apple 平台上遇到过无法轻松找到解决方案的问题,请咨询 HIG。Apple 可能根本不希望你这样做,而且他们通常(我不是 Apple,所以我不能总是保证)会在他们的文档中这么说。
嗯,如果您的应用程序需要互联网连接,您可能“必须”退出该应用程序。您可以显示警报,然后执行以下操作:
if ([[UIApplication sharedApplication] respondsToSelector:@selector(terminate)]) {
[[UIApplication sharedApplication] performSelector:@selector(terminate)];
} else {
kill(getpid(), SIGINT);
}
我们不能退出应用程序使用exit(0)
,abort()
功能,因为 Apple 强烈反对使用这些功能。尽管您可以将此功能用于开发或测试目的。
如果在开发或测试期间需要终止您的应用程序,建议使用中止函数或断言宏
请查找此 Apple Q&A线程以获取更多信息。
由于使用此功能会产生应用程序崩溃的印象。因此,我得到了一些建议,例如由于某些功能不可用,我们可以向意识到用户关闭应用程序时显示带有终止消息的警报。
但是 iOS Human Interface Guideline for Starting and Stopping App,建议不要使用 Quit 或 Close 按钮来终止应用程序。而不是他们建议显示适当的信息来解释情况。
iOS 应用从不显示关闭或退出选项。当人们切换到另一个应用程序、返回主屏幕或将他们的设备置于睡眠模式时,他们会停止使用一个应用程序。
永远不要以编程方式退出 iOS 应用程序。人们倾向于将此解释为崩溃。如果某些事情阻止了您的应用程序按预期运行,您需要告诉用户这种情况并解释他们可以做些什么。
除了以上,好,回答我只是想补充一下,想想清理一下你的记忆。
在您的应用程序退出后,iPhone OS 会自动清理您的应用程序留下的所有内容,因此手动释放所有内存只会增加您的应用程序退出所需的时间。
- (IBAction)logOutButton:(id)sender
{
//show confirmation message to user
CustomAlert* alert = [[CustomAlert alloc] initWithTitle:@"Confirmation" message:@"Do you want to exit?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
alert.style = AlertStyleWhite;
[alert setFontName:@"Helvetica" fontColor:[UIColor blackColor] fontShadowColor:[UIColor clearColor]];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != 0) // 0 == the cancel button
{
//home button press programmatically
UIApplication *app = [UIApplication sharedApplication];
[app performSelector:@selector(suspend)];
//wait 2 seconds while app is going background
[NSThread sleepForTimeInterval:2.0];
//exit app when app is in background
NSLog(@"exit(0)");
exit(0);
}
}
[[UIApplication sharedApplication] terminateWithSuccess];
它工作正常并自动调用
- (void)applicationWillTerminateUIApplication *)application delegate.
删除编译时警告添加此代码
@interface UIApplication(MyExtras)
- (void)terminateWithSuccess;
@end
我使用了上面提到的 [[NSMutableArray new] addObject:nil] 方法来强制退出(崩溃)应用程序,而无需调用 exit(0) 函数。
为什么?因为我的应用程序在所有网络 API 调用上使用证书固定来防止中间人攻击。这些包括我的金融应用程序在启动时进行的初始化调用。
如果证书身份验证失败,我的所有初始化调用都会出错并使我的应用程序处于不确定状态。让用户回家然后回到应用程序并没有帮助,因为除非应用程序已被操作系统清除,否则它仍然未初始化且不可信。
因此,在这种情况下,我们认为最好弹出警报,通知用户应用程序在不安全的环境中运行,然后当他们点击“关闭”时,使用上述方法强制退出应用程序。
用户应该决定应用程序何时退出。我认为当应用退出时这不是一个好的用户交互。因此没有很好的API,只有主页按钮有一个。
如果有错误:更好地实施或通知用户。如果必须重新启动:更好地实施通知用户。
这听起来很愚蠢,但在不让用户决定并且不通知他的情况下退出应用程序是一种不好的做法。由于有一个用于用户交互的主页按钮,Apple 表示,同一个功能(退出应用程序)不应该有两个东西。
退出主页按钮以外的应用程序确实是非 iOS 风格的方法。
不过,我做了这个助手,它不使用私人的东西:
void crash()
{ [[NSMutableArray new] addObject:NSStringFromClass(nil)]; }
但就我而言,仍然不适合生产。它用于测试崩溃报告,或在 Core Data 重置后快速重启。如果功能留在生产代码中,只是确保不会被拒绝。
如果一个应用程序是一个长期存在的应用程序,它也在后台执行,例如获取位置更新(为此使用位置更新后台功能),则退出应用程序可能是合适的。
例如,假设用户退出您的基于位置的应用程序,并使用主页按钮将应用程序推送到后台。在这种情况下,您的应用程序可能会继续运行,但完全退出它可能是有意义的。这对用户有好处(释放内存和其他不需要使用的资源),也有利于应用程序的稳定性(即确保应用程序在可能的情况下定期重启是防止内存泄漏和其他低内存的安全网问题)。
这可以(尽管可能不应该,见下文:-) 可以通过以下方式实现:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if (/* logged out */) {
exit(0);
} else {
// normal handling.
}
}
由于应用程序随后会退出后台,因此在用户看来不会出错,也不会像崩溃一样,只要用户下次运行应用程序时恢复用户界面即可。换句话说,对于用户来说,当应用程序处于后台时,它与系统启动的应用程序终止没有什么不同。
不过,最好使用更标准的方法让系统知道应用程序可以终止。例如,在这种情况下,通过停止请求位置更新来确保 GPS 未在使用中,包括关闭在地图视图上显示当前位置(如果存在)。[[UIApplication sharedApplication] backgroundTimeRemaining]
这样,系统将在应用程序进入后台几分钟(即)后终止应用程序。这将获得所有相同的好处,而无需使用代码来终止应用程序。
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if (/* logged out */) {
// stop requesting location updates if not already done so
// tidy up as app will soon be terminated (run a background task using beginBackgroundTaskWithExpirationHandler if needed).
} else {
// normal handling.
}
}
当然,根据参考http://developer.apple.com/iphone/library/qa/qa2008/qa1561.htmlexit(0)
的其他答案,使用永远不适合在前台运行的普通生产应用程序
Swift 4.2(或更早版本)
Darvin
可以使用调用的库。
import Darwin
exit(0) // Here you go
注意:这在 iOS 应用程序中不被推荐。
这样做会得到崩溃日志。
在 iPadOS 13 中,您现在可以像这样关闭所有场景会话:
for session in UIApplication.shared.openSessions {
UIApplication.shared.requestSceneSessionDestruction(session, options: nil, errorHandler: nil)
}
这将调用applicationWillTerminate(_ application: UIApplication)
您的应用程序委托并最终终止应用程序。
但要注意两点:
这当然不是用来关闭所有场景的。(见https://developer.apple.com/design/human-interface-guidelines/ios/system-capabilities/multiple-windows/)
它在 iPhone 上的 iOS 13 上编译并运行良好,但似乎什么也没做。
有关 iOS/iPadOS 13 中场景的更多信息:https ://developer.apple.com/documentation/uikit/app_and_environment/scenes