ChatGPT解决这个技术问题 Extra ChatGPT

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

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

只有一种正确的方法 - 主页按钮..
我能想象的任何人考虑以编程方式退出的唯一情况是以下情况:应用程序启动,显示使用条款,拒绝接受然后退出应用程序。这是品牌有时会迫使开发商做的事情。但这是错误的。
@Daniel 通常,您在上传应用程序时会将免责声明/使用条款 (EULA) 放在 iTunes Connect 上。如果用户下载您的应用程序,则表示他们已接受您的 EULA
需要强制退出 ios 应用程序有完全正当的理由。我的情况是我正在分发我的应用程序的发布前测试版。测试版免费开放所有 IAP。这些有时间限制,需要在几周后到期。所以我在测试期结束后使用下面的答案来杀死应用程序。我将在 LIVE 版本中删除它。但是答案仍然对我有所帮助并且是正确的!
退出应用程序的一个正当理由是,如果它是一个长期存在的后台执行应用程序,并且该应用程序进入了不再需要在后台运行的状态。例如,用户注销。在这种情况下,退出是有意义的,这样当应用程序下次启动时它就会开始干净。除其他原因外,这将作为防止内存泄漏的安全网。请注意,在这种情况下,应用程序将退出后台,因此用户不会注意到任何错误。

A
August

在 iPhone 上没有退出应用程序的概念。应该导致应用退出的唯一操作是触摸手机上的主页按钮,这不是开发人员可以访问的。

根据 Apple 的说法,您的应用程序不应自行终止。由于用户没有点击 Home 按钮,因此任何返回到 Home 屏幕的操作都会给用户留下您的应用程序崩溃的印象。这是令人困惑的非标准行为,应该避免。


正如我所说,这是非标准行为,应该避免。 iPhone 应用程序不是桌面应用程序。不要这样对待他们。
我可以理解苹果的意见,但我有类似的情况,我的应用程序需要互联网访问,如果它不可用,他们应该能够离开应用程序,而不仅仅是收到错误消息
我们有帮助人们睡眠的应用程序。他们希望应用程序在一段时间后终止,以减少电池消耗。我认为这种情况是可以接受的——因为用户希望睡着并且不能手动退出应用程序。
我还是不同意。当他们醒来时,应用程序“消失”了,让用户想知道发生了什么。相反,在你的应用程序中设置一个计时器,然后当时间到了,让应用程序空闲——没有活动。一个完全不做任何事情的应用程序不会耗尽电池。Springboard 也是一个应用程序——它不会仅仅为了节省能源而关闭。相反,它只是等待用户输入。
这并不能真正回答问题。它是 100% 准确的,但我认为理想情况下应该是对 OP 的问题或已接受的答案的评论。
S
Sophie Alpert

你试过exit(0)吗?

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


由于这样做是 Apple 的禁忌(可能会导致您的应用在非标准界面的应用商店中被拒绝),因此将 August 的答案视为“正确的答案”。仅供参考,这个答案(Brett's)对于所有 C 程序都是正确的,而 NSThread 对于所有 Cocoa 程序都是正确的。
在技术问答 QA1561 中,Apple 强烈反对使用退出,因为它会使应用程序看起来已经崩溃。 developer.apple.com/iphone/library/qa/qa2008/qa1561.html
[[NSThread mainThread] exit] 导致您的应用程序崩溃,因为 exit 不是实例方法。 exit(0) 会将应用程序发送到 iOS 4 的后台。再次调用 exit(0) 将使其崩溃。至少在模拟器中。
我理解为什么这么多人反对这个,但是给我们开发者一些信任怎么样?我们都是成年人,我们想知道这个功能。我发现它对于内部 QA 构建非常有用,当我第一次搜索它时,很高兴看到这个“不正确”的答案。
@Kevin“不要那样做”永远不是正确的答案。如果您愿意,请提供警告和免责声明,但“我该怎么做”的唯一正确答案是“这是怎么做的”。如果我正在寻找如何做某事(也许我想在调试时强制它退出),人们会正确地声明“你没有!”试图掩盖我需要的答案是在浪费我的时间。不管很多人做某事可能有不好的理由,正确的 StackOverflow 答案是回答问题的答案,因为有充分理由的人也会寻找解决问题的方法。
M
MaxEcho

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

苹果会批准这个“exit(0)”吗?因为有人说当你使用 exit 0 时苹果会拒绝你的应用。
@GajendraKChauhan exit(0) 没关系。重点是您的应用程序具有“退出行为”。退出行为本身在 AppStore 中是被禁止的,除了一些非常重要的第三方制作的应用程序。此外,模仿主页按钮的行为也会被拒绝。
Y
Yi Jiang

在此处查看问答:https://developer.apple.com/library/content/qa/qa1561/_index.html

问:如何以编程方式退出我的 iOS 应用程序?没有提供用于优雅终止 iOS 应用程序的 API。在 iOS 中,用户按下 Home 按钮来关闭应用程序。如果您的应用程序存在无法提供其预期功能的情况,推荐的方法是向用户显示警报,指出问题的性质以及用户可能采取的措施——打开 WiFi、启用定位服务等。允许用户自行决定终止应用程序。警告:不要调用退出函数。调用 exit 的应用程序将在用户看来已经崩溃,而不是执行正常终止并动画返回主屏幕。此外,可能不会保存数据,因为如果您调用 exit,将不会调用 -applicationWillTerminate: 和类似的 UIApplicationDelegate 方法。如果在开发或测试期间需要终止您的应用程序,建议使用中止函数或断言宏


刚刚添加了一个没有按钮的 AlertView 来遵守这一点。简单的。
很好的答案,刚刚使用 exit(0) 并且不知道它属于私有 api
佚名

它并不是真正的退出程序的方法,而是一种迫使人们退出的方法。

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];

至少在模拟器上,如果你这样做,当用户重新打开应用程序时,警报仍然存在。因此,我建议给他们至少一个按钮。
使用 Kalyan 的答案,以便在按下主页按钮时退出应用程序。
这样做的问题是它实际上并没有退出应用程序,因此除非用户滑动应用程序,否则开发人员可能想要通过退出来完成的任何事情(抛出无效/旧 UI、清除常量等)都不会执行关闭。
这不会杀死应用程序。
K
Kalyan

转到您的 info.plist 并检查“应用程序不在后台运行”键。这一次,当用户单击主页按钮时,应用程序完全退出。


但是后台进程也会被解雇。
T
TheTiger

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


可以在运行时更改此设置吗?我的意思是,我想在后台运行,除非我的应用程序选择在下一次暂停时退出——此时我将要介绍 UIApplicationExitsOnSuspend。这可能吗?
R
Romain Champourlier

经过一些测试,我可以说以下内容:

使用私有接口: [UIApplication sharedApplication] 将导致应用程序看起来像崩溃了,但在这样做之前它会调用 - (void)applicationWillTerminate:(UIApplication *)application;

使用退出(0);也将终止应用程序,但它看起来“正常”(跳板的图标看起来像预期的那样,具有缩小效果),但它不会调用 - (void)applicationWillTerminate:(UIApplication *)application 委托方法。

我的建议:

在委托上手动调用 - (void)applicationWillTerminate:(UIApplication *)application。调用退出(0);。


Apple 表示不使用退出,因为“调用退出的应用程序在用户看来已经崩溃,而不是执行正常终止并动画返回主屏幕”developer.apple.com/library/ios/#qa/qa2008/qa1561.html
L
L'g

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

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

当我收到此通知时,我只是打电话

        exit(0);

哪个可以完成所有工作。最好的事情是,用户打算退出,这就是为什么在那里调用它应该不是问题的原因。

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

因此,我设置了一个标志,以便在下一个后台操作时真正退出应用程序。同步后刷新应用程序是可以的。


这不是一个好的解决方案,因为应用程序将因其他原因退出活动状态,例如来电。
解决方案是添加一个仅在有用时才退出的检查。例如,如果用户在开始屏幕上。那么即使有电话打进来也没关系。自从我的应用程序中的 iOS 2 以来,Apple 并没有拒绝这一点。 stackoverflow.com/a/43906936/712124
佚名

我的应用程序最近被拒绝,因为我使用了一种未记录的方法。字面上地:

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

“3.3.1 应用程序只能以 Apple 规定的方式使用文档化 API,不得使用或调用任何私有 API。”

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


A
AGPX

苹果说:

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

我认为这是一个糟糕的假设。如果用户点击退出按钮并出现一条消息,例如:“应用程序现在将退出。”,它似乎没有崩溃。 Apple 应该提供一种有效的方式来退出应用程序(而不是 exit(0))。


他们称之为 Home 按钮,它可以位于任何 iDevice 的底部。因此,因此永远不需要在其中构建自己的退出按钮。
T
TheTiger

您不应直接调用函数 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()
     }
}

n
nanonyme

这已经得到了一个很好的答案,但决定扩大一点:

如果不仔细阅读 Apple 的 iOS 人机界面指南,您的应用程序将无法被 AppStore 接受。 (他们保留拒绝您对他们做任何事情的权利)“不要以编程方式退出”部分http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices.html是在这种情况下您应该如何处理的确切指南。

如果您在 Apple 平台上遇到过无法轻松找到解决方案的问题,请咨询 HIG。 Apple 可能根本不希望你这样做,而且他们通常(我不是 Apple,所以我不能总是保证)会在他们的文档中这么说。


R
Rob

嗯,如果您的应用程序需要互联网连接,您可能“必须”退出该应用程序。您可以显示警报,然后执行以下操作:

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

不,您不必终止它。例如,当 iTunes 应用程序无法检测到正确的连接时,它只会显示一个屏幕,显示它们未连接。它不会退出,它只是通知用户正在发生的事情。然后用户通过点击主页按钮退出。
但是,如果指南针应用程序无法运行,它就会退出。
t
technerd

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

如果在开发或测试期间需要终止您的应用程序,建议使用中止函数或断言宏

请查找此 Apple Q&A 线程以获取更多信息。

由于使用此功能会产生应用程序崩溃的印象。因此,我得到了一些建议,例如由于某些功能不可用,我们可以向意识到用户关闭应用程序时显示带有终止消息的警报。

但是针对 Starting And Stopping App 的 iOS 人机界面指南,建议永远不要使用退出或关闭按钮来终止应用程序。而不是他们建议显示适当的信息来解释情况。

iOS 应用从不显示关闭或退出选项。当人们切换到另一个应用程序、返回主屏幕或将他们的设备置于睡眠模式时,他们会停止使用一个应用程序。永远不要以编程方式退出 iOS 应用程序。人们倾向于将此解释为崩溃。如果某些事情阻止了您的应用程序按预期运行,您需要告诉用户这种情况并解释他们可以做些什么。


C
Chris Jefferson

除了以上,好,回答我只是想补充一下,想想清理一下你的记忆。

在您的应用程序退出后,iPhone OS 会自动清理您的应用程序留下的所有内容,因此手动释放所有内存只会增加您的应用程序退出所需的时间。


请在 IOS4.0 和 UP 的当前情况下修改您的答案.. :P
A
ANeme
- (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);
  }
}

M
Michael Long

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

为什么?因为我的应用程序在所有网络 API 调用上使用证书固定来防止中间人攻击。这些包括我的金融应用程序在启动时进行的初始化调用。

如果证书身份验证失败,我的所有初始化调用都会出错并使我的应用程序处于不确定状态。让用户回家然后回到应用程序并没有帮助,因为除非应用程序已被操作系统清除,否则它仍然未初始化且不可信。

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


我看不出是什么阻碍了您显示单个全屏普通警报,告诉用户该应用程序由于“证书固定”原因而无法使用,仅此而已。用户最终将关闭应用程序。你可能不知道,但 iOS 保留杀死你的进程(保持其状态)并在以后恢复它的权利,iOS 应用程序的“生命周期”并不真正掌握在你手中。您的崩溃 - 只是一次崩溃,操作系统可能会选择恢复应用程序。
哇,三年前的帖子。无论如何,新的应用程序架构几乎可以做到这一点,使用重试按钮重试 API 并丢弃块屏幕,或者将它们返回到带有新错误的块屏幕。
旧的应用程序结构几乎不允许任何重试启动 API 调用的好方法,并且没有它们,应用程序处于不一致的状态。我们本可以使用永久屏蔽屏幕,但这需要用户自己强制退出应用程序,因此并非每个用户都知道如何双击并强制退出应用程序。今天更容易,但三年前相当隐蔽。
B
Bhavin Bhadani
[[UIApplication sharedApplication] terminateWithSuccess];

它工作正常并自动调用

- (void)applicationWillTerminateUIApplication *)application delegate.

删除编译时警告添加此代码

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

这是一种私人方法,Diego Mercado 上面已经解释过他的应用程序被拒绝了,那么为什么要冒这样的风险。
使用私有 API 会导致应用被 Apple 拒绝。
对于企业应用程序 - 这可以是一个解决方案。
- (IBAction)exitApp:(id)sender { SEL 选择器 = NSSelectorFromString(@"terminateWithSuccess"); [self performSelector:selector withObject:[UIApplication sharedApplication]]; }
@unmircea 是否通过了审核?
B
Binarian

用户应该决定应用程序何时退出。我认为当应用退出时这不是一个好的用户交互。因此没有很好的API,只有主页按钮有一个。

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

这听起来很愚蠢,但在不让用户决定并且不通知他的情况下退出应用程序是一种不好的做法。由于有一个用于用户交互的主页按钮,Apple 表示,同一个功能(退出应用程序)不应该有两个东西。


G
Geri Borbás

退出主页按钮以外的应用程序确实是非 iOS 风格的方法。

不过,我做了这个助手,它不使用私人的东西:

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

但就我而言,仍然不适合生产。它用于测试崩溃报告,或在 Core Data 重置后快速重启。如果功能留在生产代码中,只是确保不会被拒绝。


f
frankodwyer

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

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

这可以(尽管可能不应该,见下文:-) 可以通过以下方式实现:

- (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.html 的其他答案,使用 exit(0) 永远不适合在前台运行的普通生产应用程序


S
Saranjith

Swift 4.2(或更早版本)

可以使用名为 Darvin 的库。

import Darwin

exit(0) // Here you go

注意:这在 iOS 应用程序中不被推荐。

这样做会得到崩溃日志。


K
Klaas

在 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