我正在编写iPhone应用程序,由于某些用户操作,我需要强制其退出。清理分配给应用程序的内存后,调用哪种方法终止应用程序?
我正在编写iPhone应用程序,由于某些用户操作,我需要强制其退出。清理分配给应用程序的内存后,调用哪种方法终止应用程序?
Answers:
你试过了exit(0)
吗?
或者,[[NSThread mainThread] exit]
尽管我没有尝试过,但这似乎是更合适的解决方案。
在iPhone上,没有退出应用程序的概念。导致应用程序退出的唯一动作是触摸手机上的“主页”按钮,而这不是开发人员可以访问的。
根据苹果公司的说法,您的应用程序不应自行终止。由于用户没有点击“主页”按钮,因此任何返回主屏幕的操作都会给用户留下您的应用崩溃的印象。这是令人困惑的非标准行为,应该避免。
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)
没关系。重点是您的应用程序具有“退出行为”。除了非常重要的第三方制作的一些应用程序外,AppStore本身也禁止退出行为。同样,模仿主页按钮的行为也将被拒绝。
在此处检查问答:https : //developer.apple.com/library/content/qa/qa1561/_index.html
问:如何以编程方式退出我的iOS应用程序?
没有提供用于正常终止iOS应用程序的API。
在iOS中,用户按下“主页”按钮以关闭应用程序。如果您的应用程序存在无法提供其预期功能的情况,建议的方法是向用户显示警报,以指示问题的性质以及用户可能采取的措施-开启WiFi,启用定位服务等。允许用户自行决定终止应用程序。
警告:请勿调用该
exit
函数。exit
在用户看来,应用程序调用将崩溃,而不是执行正常的终止并动画返回主屏幕。此外,数据可能无法保存,因为
-applicationWillTerminate:
和UIApplicationDelegate
如果您调用exit,则不会调用方法。如果在开发或测试期间有必要终止应用程序,则建议使用
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];
将UIApplicationExitsOnSuspend
属性添加application-info.plist
到true
。
经过一些测试,我可以说以下内容:
[UIApplication sharedApplication]
将导致应用看上去像崩溃了,但是它将调用- (void)applicationWillTerminate:(UIApplication *)application
在此之前;exit(0);
也会终止该应用程序,但是它将看起来“正常”(跳板的图标看起来像预期的那样,具有缩小效果),但是不会调用- (void)applicationWillTerminate:(UIApplication *)application
委托方法。我的建议:
- (void)applicationWillTerminate:(UIApplication *)application
代理。exit(0);
。您的ApplicationDelegate收到用户有意退出的通知:
- (void)applicationWillResignActive:(UIApplication *)application {
收到此通知后,我只打电话给
exit(0);
哪个工作全部完成。最好的是,这是用户退出的意图,这就是为什么在此调用它应该不是问题。
在我的音频应用程序上,当人们仍在播放音乐的同时同步他们的设备后,有必要退出该应用程序。同步完成后,我会收到一条通知。但是在那之后立即退出应用程序实际上看起来像是崩溃。
因此,我设置了一个标志,以在下一个后台操作真正退出该应用程序。同步后刷新应用程序是可以的。
我的应用最近被拒绝了,因为我使用了未公开的方法。从字面上看:
“很遗憾,由于它使用的是私有API,因此无法添加到App Store。禁止使用非公共API,如iPhone开发者计划许可协议第3.3.1节所述:
“ 3.3.1应用程序只能按照Apple规定的方式使用文档化的API,不得使用或调用任何私有API。”
您的应用程序中包含的非公共API是TerminateWithSuccess“
这已经得到了很好的答案,但是决定扩大一点:
您必须很好地阅读Apple的iOS人机界面指南,才能使您的应用程序被AppStore接受。(他们保留拒绝您对他们采取任何行动的权利)“请勿以编程方式退出”部分http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices。 html 是在这种情况下应如何处理的确切指南。
如果您在Apple平台上遇到问题,无法轻松找到解决方案,请咨询HIG。Apple可能根本不希望您这样做,他们通常(我不是Apple,所以我不能保证总是)在他们的文档中这样说。
嗯,例如,如果您的应用程序需要Internet连接,则您可能“必须”退出该应用程序。您可以显示警报,然后执行以下操作:
if ([[UIApplication sharedApplication] respondsToSelector:@selector(terminate)]) {
[[UIApplication sharedApplication] performSelector:@selector(terminate)];
} else {
kill(getpid(), SIGINT);
}
我们不能退出应用程序中使用exit(0)
,abort()
功能,苹果公司强烈反对使用这些功能。虽然您可以将此功能用于开发或测试目的。
如果在开发或测试期间有必要终止应用程序,则建议使用abort函数或assert宏
请找到此Apple 问答线程以获取更多信息。
使用此功能后,会产生像应用程序崩溃的印象。因此,我得到了一些建议,例如由于某些功能不可用,我们可以显示带有终止消息的警报,以通知用户有关关闭该应用程序的信息。
但是iOS用于启动和停止应用程序的 iOS人机界面指南建议不要使用“退出”或“关闭”按钮来终止应用程序。相反,他们建议显示适当的消息以说明情况。
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);
}
}
我使用了上面提到的[[NSMutableArray new] addObject:nil]方法来强制退出(崩溃)该应用程序,而无需执行一个讲故事的exit(0)函数调用。
为什么?因为我的应用程序在所有网络API调用上使用证书固定,以防止中间人攻击。这些包括我的金融应用在启动时进行的初始化调用。
如果证书身份验证失败,我的所有初始化调用都会出错,并使我的应用程序处于不确定状态。让用户回家然后再返回应用程序无济于事,因为除非该应用程序已被操作系统清除,否则它仍未初始化且不可信任。
因此,在这种情况下,我们认为最好弹出一个警报,通知用户该应用程序在不安全的环境中运行,然后在用户单击“关闭”时,使用上述方法强制退出该应用程序。
[[UIApplication sharedApplication] terminateWithSuccess];
工作正常,可以自动调用
- (void)applicationWillTerminateUIApplication *)application delegate.
删除编译时警告添加此代码
@interface UIApplication(MyExtras)
- (void)terminateWithSuccess;
@end
您不应该直接调用该函数 exit(0)
因为它将立即退出应用程序,并且看起来您的应用程序已崩溃。因此最好向用户显示确认警报,然后让他们自己执行此操作。
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()
}
}
除了主页按钮以外的其他方式退出应用程序,这实际上不是iOS风格的方法。
不过,我做了这个帮手,没有使用任何私人物品:
void crash()
{ [[NSMutableArray new] addObject:NSStringFromClass(nil)]; }
但就我而言,这仍然不适合生产。它用于测试崩溃报告,或在重置核心数据后快速重启。只是为了确保不遗漏生产代码中的功能,这是安全的。
在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
如果应用程序是一个寿命很长的应用程序,并且该应用程序也在后台执行,则可能适合退出该应用程序,例如获取位置更新(为此使用位置更新后台功能)。
例如,假设用户注销了您基于位置的应用,然后使用“主页”按钮将应用推到后台。在这种情况下,您的应用程序可能会继续运行,但是完全退出它可能很有意义。这对用户有利(释放不需要使用的内存和其他资源),对应用程序稳定性也有好处(即确保在可能的情况下定期重新启动应用程序是防止内存泄漏和其他内存不足的安全网)问题)。
这可以(尽管可能不应该,请参见下文:-)通过以下方式实现:
- (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的其他答案,使用永远不会适合在前台运行的普通生产应用程序。