0

I need a firestore function to execute when the user terminates the app. Specifically, I need to delete a document in firestore. I used the applicationWillTerminate in the AppDelegate for that.

This is the code:

func applicationWillTerminate(_ application: UIApplication) {
        
        print("App terminated")
        
        guard let email = UserDefaults.standard.value(forKey: "email") as? String else {
            return
        }
        let safeEmail = DatabaseManager.safeEmail(emailAddress: email)
        Firestore.firestore().collection("LocationsList").document(safeEmail).delete() { err in
            if let err = err {
                print("Error removing document: \(err)")
            }
            else {
                print("Document removed")
            }
        }
        
    }

Terminal successfully prints "App terminated" meaning that the function is called when the user terminates the app. However, the Firestore call doesn't completely execute, which I would believe is due to the short time limit the applicationWillTerminate has. Is there any way I can get the Firestore document to delete/the call to execute completely?

Jay
  • 34,438
  • 18
  • 52
  • 81
  • What do you mean it doesn't "completely execute"? Do you mean that the function successfully deletes the document but doesn't call the completion handler? – trndjc Dec 03 '22 at 16:51
  • The common solution is to request that the OS keep your app running in the background until the requested task is done, via [`beginBackgroundTask`](https://developer.apple.com/documentation/uikit/uiapplication/1623051-beginbackgroundtask). See also https://developer.apple.com/forums/thread/85066/. – Rob Dec 03 '22 at 17:23
  • I answered a similar question here: https://stackoverflow.com/a/74593708/5318223 Don't schedule new work in `...WillTerminate` method, do it in `...WillResignActive(_:)` instead – timbre timbre Dec 03 '22 at 18:27
  • @trndjc The document is not deleted in Firestore – Yoshua Kaempf Dec 04 '22 at 05:33
  • @Rob If I'm not mistaken beginBackgroundTask only executes when the app is in the background and NOT when the user terminates the app (completely closes out of it). If I got that wrong please let me know – Yoshua Kaempf Dec 04 '22 at 05:36
  • @akjndklskver The problem is that I'm doing different things if the app is only running in the background. I only want to delete the document when the app is terminated, NOT when the app is running in the background – Yoshua Kaempf Dec 04 '22 at 05:37
  • Yes, `beginBackgroundTask` is used when the user leaves the app, and you want a little extra time of background execution before the app is suspended. But you generally do that when the app resigns its active state. You obviously cannot enjoy background execution at all if the app is terminated. But, I assume you know that `applicationWillTerminate` is of limited utility: Sure, it detects if the user kills an active app. But what if the user leaves the app and kills it later, when it's not active? The `applicationWillTerminate` is not called. You never know that the user killed the app. – Rob Dec 04 '22 at 07:34
  • Thank y'all for your help, that led me to look into some of the other functions available, and I seemed to have solved the problem by using the sceneDidDisconnect in the SceneDelegate. It executes and deletes the Firestore document successfully when the user kills the app and should also do so when the app is too long in the background and released by the system. – Yoshua Kaempf Dec 04 '22 at 09:20

1 Answers1

0

I have solved the problem by implementing the code in the sceneDidDisconncet in the SceneDelegate instead of the applicationWillTerminate. This works well for what I was trying to achieve and the Firestore document is deleted when the user kills/terminates the app. This is the code snippet (in the SceneDelegate):

func sceneDidDisconnect(_ scene: UIScene) {
    //print("inactive")
    guard let email = UserDefaults.standard.value(forKey: "email") as? String else {
                return
            }
            let safeEmail = DatabaseManager.safeEmail(emailAddress: email)
            Firestore.firestore().collection("LocationsList").document(safeEmail).delete() { err in
                if let err = err {
                    print("Error removing document: \(err)")
                }
                else {
                    print("Document removed")
                }
            }
    // Called as the scene is being released by the system.
    // This occurs shortly after the scene enters the background, or when its session is discarded.
    // Release any resources associated with this scene that can be re-created the next time the scene connects.
    // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}