Я программирую приложение для iPhone, и мне нужно заставить его выйти из-за определенных действий пользователя. После очистки памяти, выделенной приложению, какой метод следует вызвать для завершения приложения?
Я программирую приложение для iPhone, и мне нужно заставить его выйти из-за определенных действий пользователя. После очистки памяти, выделенной приложению, какой метод следует вызвать для завершения приложения?
Ответы:
Ты пробовал exit(0)
?
В качестве альтернативы, [[NSThread mainThread] exit]
хотя я не пробовал, это кажется более подходящим решением.
На iPhone нет концепции выхода из приложения. Единственное действие, которое должно привести к закрытию приложения, - это нажать кнопку «Домой» на телефоне, и разработчики не имеют к этому доступа.
Согласно Apple, ваше приложение не должно завершаться само по себе. Поскольку пользователь не нажимал кнопку «Домой», любой возврат к главному экрану создает у пользователя впечатление, что ваше приложение не работает. Это запутанное, нестандартное поведение, и его следует избегать.
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?
Не предусмотрено API для изящного завершения приложения iOS.
В 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];
Зайдите в ваш info.plist и проверьте ключ «Приложение не запускается в фоновом режиме». На этот раз, когда пользователь нажимает кнопку «Домой», приложение полностью закрывается.
Добавить 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);
Который делает всю работу. И самое главное, это намерение пользователей выйти, поэтому это не должно быть проблемой, вызывая его там.
В моем Audio-App было необходимо выйти из приложения после того, как люди синхронизировали свое устройство, пока музыка еще играла. Как только синхронизация завершена, я получаю уведомление. Но выход из приложения сразу после этого будет выглядеть как сбой.
Поэтому вместо этого я установил флаг, чтобы ДЕЙСТВИТЕЛЬНО выйти из приложения при следующем фоновом действии. Что нормально для обновления приложения после синхронизации.
Мое приложение было отклонено недавно, потому что я использовал недокументированный метод. Буквально:
«К сожалению, его нельзя добавить в App Store, поскольку он использует частный API. Использование непубличных API, как описано в разделе 3.3.1 Лицензионного соглашения программы для разработчиков iPhone, запрещено:
«3.3.1 Приложения могут использовать документированные API только в порядке, установленном Apple, и не должны использовать или вызывать какие-либо частные API».
Непубличный API, включенный в ваше приложение, является terminateWithSuccess "
Apple говорит:
«Предупреждение: не вызывайте функцию выхода. Приложения, вызывающие выход, будут казаться пользователю потерпевшим крах, а не выполнять постепенное завершение и анимацию обратно на главный экран».
Я думаю, что это плохое предположение. Если пользователь нажимает кнопку «Выход» и появляется сообщение, в котором говорится что-то вроде: «Теперь приложение будет закрыто», значит, оно не будет аварийно завершено. Apple должна предоставить правильный способ выхода из приложения (не выход (0)).
Это получил хороший ответ, но решил немного расширить:
Вы не можете принять ваше приложение в AppStore, если не будете внимательно читать Руководство по интерфейсу iOS для Apple. (они сохраняют за собой право отклонить вас делать что - либо против них) Раздел «Не Quit» Программная 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, чтобы получить больше информации.
Как использование этой функции создает впечатление, что приложение падает. Поэтому у меня появилось предположение, что мы можем отобразить Alert с сообщением о завершении для осведомленного пользователя о закрытии приложения из-за недоступности определенных функций.
Но 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], чтобы принудительно завершить (аварийно завершить работу) приложение без вызова контрольной функции выхода (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()
}
}
Пользователь должен решить, когда приложение выйдет. Я не думаю, что это хорошее взаимодействие с пользователем, когда приложение закрывается. Поэтому для него нет приятного API, он есть только у кнопки home.
Если есть ошибка: лучше ее внедрите или оповестите пользователя. Если должен быть перезапуск: Внедрите его лучше. Сообщите пользователю.
Звучит глупо, но это плохая практика - выходить из приложения, не позволяя пользователю решать и не уведомляя его. И, как утверждает Apple, поскольку есть кнопка «Домой» для взаимодействия с пользователем, не должно быть двух вещей для одной и той же функции (выход из приложения).
Выход из приложения другим способом, кроме кнопки «Домой», на самом деле не в стиле 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/ )
Он компилируется и прекрасно работает на iOS 13 на iPhone, но, похоже, ничего не делает.
Дополнительная информация о сценах в 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