Я програмую додаток для 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?
Для граціозного завершення програми iOS не передбачено API.
В iOS користувач натискає кнопку «Головна», щоб закрити програми. Якщо у вашій програмі є умови, в яких вона не може забезпечити передбачувану функцію, рекомендований підхід полягає у відображенні попередження для користувача, яке вказує на характер проблеми та можливі дії, які може вжити користувач - включення WiFi, включення служб локації тощо. Дозволити користувачеві скасувати додаток на власний розсуд.
ПОПЕРЕДЖЕННЯ: Не викликайте
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];
Перейдіть до свого інформаційного списку та перевірте клавішу "Програма не працює у фоновому режимі". Цього разу, коли користувач натискає кнопку будинку, додаток повністю закривається.
Додати 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);
Яка вся робота. І найкраще, це те, що використання має намір кинути, тому це не повинно бути проблемою його виклику там.
У моєму аудіо-додатку потрібно було вийти з програми після того, як люди синхронізували свій пристрій, поки музика ще грала. Як тільки синхронізація завершена, я отримую сповіщення. Але вихід із програми відразу після цього насправді буде схожий на збій.
Тому замість цього я встановив прапор, ЩО ЗАСТОСУВАТИ закрити програму на наступну дію фонового зображення. Що добре для оновлення програми після синхронізації.
Моє додаток нещодавно відхилено. Натомість я використав метод без документації. Буквально:
"На жаль, його не можна додати до App Store, оскільки він використовує приватний API. Використання непублічних API, як зазначено в розділі 3.3.1 Ліцензійної угоди програми для розробників iPhone, заборонено:
"3.3.1 Програми можуть використовувати лише документально підтверджені API в порядку, визначеному Apple, і не повинні використовувати або викликати приватні API."
Непублічний API, який включений у вашу заявку, є terminateWithSuccess "
Apple кажуть:
"Попередження: не викликайте функцію виходу. Програми, що викликають вихід, здадуться користувачеві збоєм, замість того, щоб виконати витончене припинення та анімацію назад на головний екран."
Я думаю, що це погане припущення. Якщо користувач натисне кнопку "Вийти" і з'явиться повідомлення, яке говорить про щось на зразок: "Додаток зараз вийде.", Воно, здається, не працює. Apple має надати дійсний спосіб виходу з програми (не вихід (0)).
Це отримало хорошу відповідь, але вирішив трохи розширитись:
Ви не можете прийняти вашу заявку до AppStore, не прочитавши добре Правил Apple iOS Human Interface. (вони залишають за собою право відхиляти вас за те, щоб зробити що- небудь проти них) Розділ "Не кидайте програмно" 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 тему щоб отримати більше інформації.
Під час використання цієї функції створюється враження, ніби програма виходить з ладу. Отож, я отримав кілька пропозицій, як ми можемо відобразити Повідомлення з повідомленням про припинення, щоб обізнаний користувач про закриття програми через відсутність певної функціональності.
Але керівництво 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]] 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, лише кнопка домашнього має його.
Якщо є помилка: Реалізуйте її краще або Повідомте користувача. Якщо потрібно здійснити перезавантаження: виконайте це краще, ніж сповістити користувача.
Це звучить глупо, але погана практика виходити з програми, не дозволяючи користувачеві приймати рішення та не повідомляти про нього. А оскільки існує домашня кнопка для взаємодії з користувачем, заявляє Apple, не повинно бути двох речей для тієї самої функції (вихід із програми).
Вихід із програми в інший спосіб, ніж кнопка додому, насправді не є iOS-esque .
Я зробив цей помічник, але не використовував приватних речей:
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-capa sposobnosti/ 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