正确的方式退出iPhone应用程序?

我正在编程一个iPhone应用程序,我需要强制它退出由于某些用户操作。在清理应用程序分配的内存后,调用什么方法来终止应用程序?

248622 次浏览

你试过exit(0)吗?

或者,[[NSThread mainThread] exit],虽然我没有尝试过,它似乎是更合适的解决方案。

除了上面的,很好,答案我只想补充一下,想想清理你的记忆。

应用程序退出后,iPhone操作系统将自动清理应用程序遗留的所有内容,因此手动释放所有内存只会增加应用程序退出所需的时间。

在iPhone上,没有退出应用的概念。导致应用退出的唯一操作是触摸手机上的Home键,而这不是开发者可以访问的。

根据苹果公司的说法,你的应用程序不应该自行终止。因为用户没有点击Home键,所以任何返回到Home屏幕的操作都会给用户留下应用程序崩溃的印象。这是令人困惑的,不规范的行为,应该避免。

嗯,如果你的应用需要网络连接,你可能“不得不”退出应用程序。你可以显示一个警告,然后做这样的事情:

if ([[UIApplication sharedApplication] respondsToSelector:@selector(terminate)]) {
[[UIApplication sharedApplication] performSelector:@selector(terminate)];
} else {
kill(getpid(), SIGINT);
}

经过一些测试,我可以这样说:

  • 使用私有接口:[UIApplication sharedApplication]将导致应用程序看起来已经崩溃,但它将在这样做之前调用- (void)applicationWillTerminate:(UIApplication *)application;
  • 使用exit(0);也将终止应用程序,但它看起来“正常”(跳板的图标与预期的一样,具有缩小效果),但它不会调用- (void)applicationWillTerminate:(UIApplication *)application委托方法。

我的建议:

  1. 手动调用委托上的- (void)applicationWillTerminate:(UIApplication *)application
  2. exit(0);打电话。

这并不是一种退出项目的方法,而是一种强迫人们退出的方法。

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];
[[UIApplication sharedApplication] terminateWithSuccess];

它工作正常,自动调用

- (void)applicationWillTerminateUIApplication *)application delegate.

要删除编译时警告,请添加以下代码

@interface UIApplication(MyExtras)
- (void)terminateWithSuccess;
@end

我的应用程序最近被拒绝了,因为我使用了一个无文件记录的方法。字面意思:

“不幸的是,它不能添加到App Store,因为它使用的是私有API。如iPhone开发者程序许可协议第3.3.1节所述,禁止使用非公共api:

“3.3.1应用程序只能按照苹果规定的方式使用文档api,不得使用或调用任何私有api。”

包含在应用程序中的非公共API是terminateWithSuccess"

检查这里的Q&A: https://developer.apple.com/library/content/qa/qa1561/_index.html

问:如何以编程方式退出iOS应用程序?

没有提供API来优雅地终止iOS应用程序。

在iOS系统中,用户按Home键关闭应用程序。如果您的应用程序在某些情况下无法提供预期的功能,建议的方法是为用户显示一个警告,指出问题的性质以及用户可以采取的可能操作——打开WiFi,启用位置服务等。允许用户自行决定终止应用程序。

警告:不调用exit函数。调用exit的应用程序将在用户看来已经崩溃,而不是执行优雅的终止并动画返回主屏幕。

此外,数据可能不会被保存,因为如果调用exit, -applicationWillTerminate:和类似的UIApplicationDelegate方法将不会被调用。

如果在开发或测试期间有必要终止应用程序,建议使用abort函数或assert

你的ApplicationDelegate收到用户有意退出的通知:

- (void)applicationWillResignActive:(UIApplication *)application {

当我收到通知时,我就打电话

        exit(0);

它做了所有的工作。最好的事情是,它是用户退出的意图,这就是为什么在那里调用它应该不是问题。

在我的音频应用中,当人们同步他们的设备而音乐仍在播放时,有必要退出应用。一旦同步完成,我就会收到通知。但在此之后立即退出应用程序实际上看起来像崩溃。

所以我设置了一个标志,在下一次背景操作时真正退出应用程序。这对于同步后刷新应用程序是可以的。

这已经得到了一个很好的答案,但我决定扩展一下:

如果你不仔细阅读苹果的iOS人机界面指南,你的应用就不可能被AppStore接受。(他们保留拒绝你对他们做任何东西的权利)部分“Don't Quit programatically”http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices.html 是一个明确的指导方针,告诉你应该如何处理这种情况。< / p >

如果你遇到苹果平台的问题,你很难找到解决方案,请咨询HIG。有可能苹果只是不想让你这么做,他们通常(我不是苹果,所以我不能保证总是)在他们的文档中这样说。

去你的信息。plist并检查关键“应用程序不运行在后台”。这一次,当用户单击home按钮时,应用程序将完全退出。

application-info.plist上的UIApplicationExitsOnSuspend属性添加到true

苹果说:

警告:不要调用exit函数。调用exit的应用程序将在用户看来已经崩溃,而不是执行优雅的终止并动画返回主屏幕。”

我认为这是一个错误的假设。如果用户点击退出按钮,出现类似“应用程序现在将退出”这样的消息,它似乎没有崩溃。苹果应该提供退出应用程序的有效方法(而不是exit(0))。

Exit(0)在用户面前显示为崩溃,因此向用户显示确认消息。确认后暂停(home键按程序),等待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);
}
}
- (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);
}
}

用户应该决定应用程序何时退出。 我不认为当应用退出时这是一种良好的用户交互。因此,它没有很好的API,只有home键有一个

如果有错误:更好地实现它或通知用户。 如果必须重新启动:实现它更好的通知用户。

这听起来很愚蠢,但在不让用户决定的情况下退出应用程序,并且不通知他,这是一种糟糕的做法。苹果表示,由于有一个home键用于用户交互,所以同一个功能(退出应用程序)不应该有两个东西。

以home键以外的方式退出应用程序是真的non-iOS-esque方法。

我做了这个助手,虽然,没有使用私人的东西:

void crash()
{ [[NSMutableArray new] addObject:NSStringFromClass(nil)]; }

但对我来说还是不适合生产。它用于测试崩溃报告,或在核心数据重置后快速重新启动。只是使它安全不被拒绝,如果功能留在生产代码。

如果应用程序是一个长期存在且在后台执行的应用程序,退出它可能是合适的,例如获取位置更新(为此使用位置更新后台功能)。

例如,假设用户退出了基于位置的应用程序,并使用home键将应用程序推到后台。在这种情况下,你的应用程序可能会继续运行,但完全退出它是有意义的。这将有利于用户(释放内存和其他不需要使用的资源),也有利于应用程序的稳定性(即确保应用程序在可能的情况下定期重新启动是防止内存泄漏和其他低内存问题的安全网)。

这可以(虽然可能不应该,见下面:-)实现如下:

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

当然,使用exit(0)永远不适合在前台运行的普通生产应用程序,因为其他答案引用http://developer.apple.com/iphone/library/qa/qa2008/qa1561.html

我使用了上面提到的[[NSMutableArray new] addObject:nil]方法来强制退出(崩溃)应用程序,而不做一个泄露的退出(0)函数调用。

为什么?因为我的应用程序在所有网络API调用上使用证书钉住,以防止中间人攻击。这些包括我的财务应用程序在启动时所做的初始化调用。

如果证书认证失败,我的所有初始化调用错误,让我的应用程序在一个不确定的状态。让用户回家然后回到应用程序并没有帮助,除非应用程序已经被操作系统清除,否则它仍然是未初始化和不值得信任的。

因此,在这种情况下,我们认为最好弹出一个警告,通知用户应用程序正在不安全的环境中运行,然后,当他们点击“关闭”时,使用上述方法强制退出应用程序。

我们不能退出应用程序使用exit(0)abort()函数,因为苹果强烈反对使用这些函数。不过,您可以将此函数用于开发或测试目的。

如果在开发或测试期间,有必要终止您的 应用程序、abort函数或assert宏建议

请找到这个Apple Q&线程来获得更多信息。

由于使用此功能创建印象,应用程序正在崩溃。所以我得到了一些建议,比如我们可以显示警报与终止消息意识到用户关闭应用程序,由于某些功能不可用。

但iOS人机界面指南为启动和停止应用程序,建议不要使用退出或关闭按钮终止应用程序。而不是他们建议展示适当的信息来解释情况。

iOS应用永远不会显示关闭或退出选项。人们不再使用 当他们切换到另一个应用程序,返回主屏幕,或放

.设备处于休眠模式 永远不要以编程方式退出iOS应用程序。人们倾向于这样解释 作为一个崩溃。如果有什么东西阻止你的应用程序运行 有意的,你需要告诉用户情况和解释什么

Swift 4.2(或更老版本)

可以使用名为Darvin的库。

import Darwin


exit(0) // Here you go

注意:在iOS应用程序中不建议这样做。

这样做会得到崩溃日志。

你不应该直接调用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()
}
}

在iPadOS 13中,你现在可以像这样关闭所有场景会话:

for session in UIApplication.shared.openSessions {
UIApplication.shared.requestSceneSessionDestruction(session, options: nil, errorHandler: nil)
}

这将在应用程序委托上调用applicationWillTerminate(_ application: UIApplication),并最终终止应用程序。

但要注意两件事:

关于iOS/iPadOS 13中的场景的更多信息:https://developer.apple.com/documentation/uikit/app_and_environment/scenes