9

I'm working on SDK and try to catch app termination Notification. It's easy to get this as closure for (ex) NSNotification.Name.UIApplicationWillResignActive

self.resignActiveNotification = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationWillResignActive,
                                                                       object: nil,
                                                                       queue: nil) { _ in
//something goes here and it works like a charm.
}

So I want to have similar behavior for termination:

self.terminateNotification = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationWillTerminate,
                                                                    object: nil,
                                                                    queue: nil) { _ in
        NSLog("%@",#function)
    }

And this one never gets called!

Of course if I put in AppDelegate:

func applicationWillTerminate(_ application: UIApplication) {
    //termination
}

It will work, but since I'm building an SDK I cannot have AppDelegate methods. There is a way to get termination closure call? Or any other way to know that application is about to terminate?

In Apple documentation you can find:

After calling this method, the app also posts a UIApplicationWillTerminate notification to give interested objects a chance to respond to the transition.

However this seems to be broken

Jakub
  • 13,712
  • 17
  • 82
  • 139
  • When exactly do you expect the notification? Compare https://stackoverflow.com/questions/7417003/applicationwillterminate-not-being-called. – Martin R Feb 28 '18 at 14:02
  • Yep, sounds good to me, I expect notification to happen when I manually kill the app that was in foreground. This is active->terminate state change – Jakub Feb 28 '18 at 14:07
  • There is no notification if the app is killed manually: https://stackoverflow.com/questions/25228933/app-delegates-applicationwillterminate-not-called-when-user-kills-app-or-shuts. – Martin R Feb 28 '18 at 14:08
  • 1
    That's not true. There is notification of state change . `applicationWillTerminate` in AppDelegate will get called if the app was in the foreground not in the suspended state. – Jakub Feb 28 '18 at 14:14
  • Please note that your code works for me, `NSLog("%@",#function)` has been called when I tried to terminate the app... Also, `NotificationCenter.default.addObserver(self, selector: #selector(doSomething), name: NSNotification.Name.UIApplicationWillTerminate, object: nil)` works fine for me – Ahmad F Feb 28 '18 at 14:15
  • 1
    As per [Apple documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623111-applicationwillterminate) this will not be called if the app gets killed by the user: `For apps that support background execution, this method is generally not called when the user quits the app because the app simply moves to the background in that case. However, this method may be called in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.` – rckoenes Feb 28 '18 at 14:57
  • 1
    @rckoenes @Martin R - there is a huge difference between suspended/background and active states. Take a look at this: https://vimeo.com/257906400 And with your quote of docs @rckoenes it says: `this method is generally not called when the user quits the app because the app simply moves to the background` so it does not refer to termination of the user, but to put it in the background. That's 2 different actions. – Jakub Feb 28 '18 at 15:09
  • True, but when the user kill the app form the task-switcher the app is dropt directly from memory. Thus the `UIApplicationWillTerminate` is not called. Only if your app will be closed because of memory pressure will the `UIApplicationWillTerminate` be called. – rckoenes Feb 28 '18 at 15:12
  • 1
    @rckoenes have a look at video from my comment before. I've done exactly that (killing app from app switcher) and it does get called. – Jakub Feb 28 '18 at 15:13
  • The method yes, but the notification no. – rckoenes Feb 28 '18 at 15:16
  • Why? Docs (https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623111-applicationwillterminate) says: `After calling this method, the app also posts a UIApplicationWillTerminate notification to give interested objects a chance to respond to the transition.` And that's the main topic of this question actually. – Jakub Feb 28 '18 at 15:18
  • I'm sure you get a `UIApplicationWillTerminate` when you kill it yourself. About the rest: I'm not sure, but when it comes to app state, it always better to kill Xcode and do your testing (even better if you use an actual device). Possibly use something like `os_log` + console + launch the app from your own clicking, not from Xcode automatic launch (Xcode interrupts app life cycle because its greedy and wants to continue its debugging). For more see [here](https://stackoverflow.com/a/25951564/5175709). Especially it's last paragraph and the link it refers to. – mfaani Feb 28 '18 at 15:32

1 Answers1

13

This seems working for me:

init() {
  NotificationCenter.default.addObserver(self,
      selector: #selector(applicationWillTerminate(notification:)),
      name: UIApplication.willTerminateNotification,
      object: nil)
}

@objc func applicationWillTerminate(notification: Notification) {
  // Notification received.
}

deinit {
  NotificationCenter.default.removeObserver(self)
}
Swapnil Jain
  • 551
  • 1
  • 6
  • 9
  • 1
    please add more description to your answer ! – Michael Maher Oct 28 '20 at 12:53
  • Please note that: "If your app targets iOS 9.0 and later or macOS 10.11 and later, and you used `addObserver(_:selector:name:object:)`, you do not need to unregister the observer. If you forget or are unable to remove the observer, the system cleans up the next time it would have posted to it." Source: https://developer.apple.com/documentation/foundation/notificationcenter/1413994-removeobserver – viteinfinite Apr 03 '22 at 22:39