Call Function on App Termination in Swift

Call function on app termination in Swift

You can register to receive a notification when your app is about to terminate. To do this, add an observer to the default notification center by

Swift 5:

 NotificationCenter.default.addObserver(self, selector: #selector(saveData), name: UIApplication.willTerminateNotification, object: nil)

Swift 3/4:

// Add this to didMoveToView in your SKScene subclass
NotificationCenter.default.addObserver(self, selector: #selector(saveData), name: NSNotification.Name.UIApplicationWillTerminate, object: nil)

Add the following method to your SKScene subclass. The method will be called before the app terminates. It must be "exposed" to Objective-C by adding @objc so the notifier can use #selector().

@objc func saveData(notification:NSNotification) {
// Save your data here
print("Saving data...")
}

SwiftUI run function when app has been terminated and then opened

This code has two different options for running code that will only run when the app is launched (eg "swiped out and then opened again").

Keep in mind that you will not see the printed lines in the debugger the second time as the debugger will not be attached to the new instance -- Xcode only attaches to the first instance that you run.

@objc class AppDelegate: NSObject, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
print("launch")
return true
}

}

@main
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

init() {
print("App runs")
}

var body: some Scene {
WindowGroup {
ContentView()
}
}
}

Since the debugger console won't show the prints on the second launch, here's an example proving that the init code runs that you can see in the UI:

@main
struct MyApp: App {
var appState = AppState()

init() {
print("App runs")
appState.count += 1
}

var body: some Scene {
WindowGroup {
ContentView(appState: appState)
}
}
}

class AppState : ObservableObject {
@Published var count = 0
}

struct ContentView : View {
@ObservedObject var appState : AppState

var body: some View {
Text("Hello: \(appState.count)")
}
}

What function gets called when an iPhone app loads again after termination?

From my understanding, didFinishLaunchingWithOptions only gets called the first load, and after any updates.

Then your understanding is wrong. It is called every time the app launches.

Which one gets called when you load for a second, third time after termination?

That would be didFinishLaunchingWithOptions.

However, let's distinguish exactly what "load" means. I've been talking about what happens when the app launches, from scratch. But it is also possible that the app will just go into the background (so the user can use another app) and then come back to the front. In that case, the app does not "load"; it was never "unloaded", so it just picks up where it left off. In that case, you'll get applicationDidBecomeActive — except for an iOS 13 native app, where the corresponding event is sent to the scene delegate.

However, your question title says that the app "loads" after termination. In that case, yes, didFinishLaunchingWithOptions is called.

Can I make an api call when the user terminates the app?

This is a two fold question

Phase 1: Ensuring API Call starts every time user terminates the app/ before it turns in active

You can always make use of expiration handler background mode of iOS application In your appdelegate

declare
var bgTask: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier(rawValue: 0);

and in your appdelegate

 func applicationDidEnterBackground(_ application: UIApplication) {

// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

bgTask = application.beginBackgroundTask(withName:"MyBackgroundTask", expirationHandler: {() -> Void in
// Do something to stop our background task or the app will be killed
application.endBackgroundTask(self.bgTask)
self.bgTask = UIBackgroundTaskIdentifier.invalid
})

DispatchQueue.global(qos: .background).async {
//make your API call here
}
// Perform your background task here
print("The task has started")
}

Background expiration handler will ensure you will get enough time to start your API call every time you put your application turns inactive or gets terminated

Phase 2: Ensuring API call started finishes successfully

Though expiration handler might ensure that you get enough time to start your API call it can't ensure the successful completion of API call. What if API call takes longer and while the request is in flight and time runs out??

The only way you to ensure that API call gets successful once started is to make sure to use proper configuration for URLSession

As per docs

Background sessions let you perform uploads and downloads of content
in the background while your app isn't running.

link: https://developer.apple.com/documentation/foundation/nsurlsession?language=objc

So make use of Background session and use upload task. Rather than having a plain get/post API which you will hit with some parameter, ask your backend developer to accept a file and put all your param data in that file (if you have any) and start an upload task with background session.

Once the upload task starts with background session iOS will take care of its completion (unless u end up in a authentication challenge obviously) even after your app is killed.

This I believe is the closest you can get to ensure starting a API call and ensuring it finishes once app gets inactive/terminated. I kind a had a discussion with a apple developer regarding the same, and they agreed that this can be a probable solution :)

hope it helps



Related Topics



Leave a reply



Submit