just wondering what will happen after performFetchWithCompletionHandler, will my app stay in the memory, or will it get purged immediately? I've googled but no one seems to be caring about this.
When this method is called, your app has up to 30 seconds of wall-clock time to perform the download operation and call the specified completion handler block. In practice, your app should call the completion handler block as soon as possible after downloading the needed data. If you do not call the completion handler in time, your app is terminated. More importantly, the system uses the elapsed time to calculate power usage and data costs for your app’s background downloads. If your app takes a long time to call the completion handler, it may be given fewer future opportunities to fetch data in the future.
Straight from Apple documentation - UIApplication Delegate
Related
I am a bit confused with how performFetchWithcompletionHandler engaged with the iOS app life cycle. In the docs it's mentioned that it gives us 30 seconds to download any data but will our app freeze for 30 seconds at that time?
... will our app freeze for 30 seconds at that time?
No, the exact opposite. This method is called when your app is suspended, but the OS is going to let you check for data to retrieve. So, your app will be awaken, run in background, and this method will be called, at which point you can perform your quick fetch (not more than 30 seconds) to see if there is any data to retrieve. When you’re done processing your quick fetch, you call the completion handler to let the OS know that you’re done and that your app can safely be suspended again.
If, though, you fail to complete your request in 30 seconds, your app may be summarily terminated and not participate in future background fetches. So it’s important to finish in the allotted time.
As the docs say:
Implement this method if your app supports the fetch background mode. When an opportunity arises to download data, the system calls this method to give your app a chance to download any data it needs. Your implementation of this method should download the data, prepare that data for use, and call the block in the completionHandler parameter.
When this method is called, your app has up to 30 seconds of wall-clock time to perform the download operation and call the specified completion handler block. In practice, your app should call the completion handler block as soon as possible after downloading the needed data. If you do not call the completion handler in time, your app is terminated. More importantly, the system uses the elapsed time to calculate power usage and data costs for your app’s background downloads. If your app takes a long time to call the completion handler, it may be given fewer future opportunities to fetch data in the future. For more information about supporting background fetch operations, see Background Execution in App Programming Guide for iOS.
This is regarding background fetch, like when an app receive silent notifications. In this case, iOS wakes up an application in background for max 30 sec. and do the stuff as per writer code and the kill the app. So user will be unaware of this.
It is not recommended to write complex logic in this method performFetchWithcompletionHandler. The reason is the time limit(30 sec.) and the app developer doesn't have a control over it.
To get this work, background mode should be enabled in capabilities of project.
One of the example about this is silent push notification (notification payload has the key content-available = 1)
For more details see this
If an application starts to perform some activity in the foreground, then it moves to the background and continues to execute for the 30 seconds that the OS lets it run for, but then within that 30 seconds it has not completed what it was doing.
Then what happens when the app next comes to the foreground? Does whatever processing it was in the middle of doing when the 30 seconds was up automatically get resumed at the point it got suspended by the OS when in the background and the 30 seconds finished?
(Similar question - suppose the app calls UIApplication.setMinimumBackgroundFetchInterval().
Then if the user moves the app to the background, it runs for 30 seconds then stops, then the OS runs it in the background due to setMinimumBackgroundFetchInterval having been called, does it resume exactly what it was doing at the end of the 30 seconds?)
No, it does not continue. It seems that the answers you are looking for can be found in this parts of the documentation (emphasis mine), depending on how you transfer tasks to the background :
https://developer.apple.com/documentation/uikit/uiapplication/1623051-beginbackgroundtask
Each call to this method must be balanced by a matching call to the endBackgroundTask(_:) method. Apps running background tasks have a finite amount of time in which to run them. (You can find out how much time is available using the backgroundTimeRemaining property.) If you do not call endBackgroundTask(_:) for each task before time expires, the system kills the app. If you provide a block object in the handler parameter, the system calls your handler before time expires to give you a chance to end the task.
https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623125-application
When this method is called, your app has up to 30 seconds of wall-clock time to perform the download operation and call the specified completion handler block. In practice, your app should call the completion handler block as soon as possible after downloading the needed data. If you do not call the completion handler in time, your app is terminated.
I am reading the source code of SDImageCache.
Basically every time before an app is killed, upon UIApplicationWillTerminateNotification, SDImageCache travels every file cached, identifies those expired and deletes them.
Would the system wait for this kind of class to finish it's job before kill that app? or the deleting process would be rudely interrupted?
Could this class ask for more time to process?
That notification is sent immediately after applicationWillTerminate: is sent to your app delegate. From UIApplicationDelegate's documentation, you have about 5 seconds.
Your implementation of this method has approximately five seconds to perform any tasks and return. If the method does not return before time expires, the system may kill the process altogether.
However, you shouldn't rely on having 5 seconds, and instead use Instruments to improve your code's performance to be as fast as possible. If you're concerned that you'll need more than 5 seconds, you can request more using beginBackgroundTaskWithExpirationHandler:.
After your application completes its actions during a background fetch you must call the completionHandler block with one of the three UIBackgroundFetchResult states: UIBackgroundFetchResultNoData, UIBackgroundFetchResultNewData, or UIBackgroundFetchResultFailed.
How are each of these three results handled by the OS once the completion handler is called?
From the iOS App App Programming guide:
When the application:performFetchWithCompletionHandler: method of your delegate is called, use that method to check for new content and to download that content if it is available. When your downloads are complete, execute the provided completion handler block, passing a result that indicates whether content was available. Executing this block tells the system that it can move your app back to the suspended state and evaluate its power usage. Apps that download small amounts of content quickly and accurately reflect when they had content to download are more likely to receive execution time in the future than apps that take longer to download their content
They don't give us so many details, but I think is clear enough: you pass the result of the fetch to the System, so it can decide when to give background execution time (and how much).
Example, consider two different apps:
- one downloads files that are updated every night
- the other downloads files that are updated more frequently, many times in a day
In both cases, the system will wake up your app, takes note of the start time, your app starts the download and then tells the system that there was or not content available.
After some time, you'll see that the system will wake up the first app less frequently than the second one, optimizing battery consumption.
Moreover, if you use NSURLSession to start you download, the system will evaluate your app's power consumption (since using NSURLSession you have "unlimited" time to download files), even this metric is used to decide how often wake up your app.
Is applicationDidEnterBackground ALWAYS called before applicationWillTerminate in an iOS app? I know that applicationWillTerminate is not always called (multitasking) - but when it is called, is applicationDidEnterBackground ALWAYS called first? I don't want to duplicate code unnecessarily by including it in applicationWillTerminate if it is already included in applicationDidEnterBackground, for an app that supports multitasking.
in ios 4.0 and later applicationDidEnterBackground is called instead of applicationWillTerminate so you don't have to call both of them. Here is the portion of the Apple docs:
Discussion
In iOS 4.0 and later, this method is called instead of the
applicationWillTerminate: method when the user quits an application
that supports background execution. You should 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. You should also
disable updates to your application’s user interface and avoid using
some types of shared system resources (such as the user’s contacts
database). It is also imperative that you avoid using OpenGL ES in the
background.
Your implementation of this method has approximately five seconds to
perform any tasks and return. If you need additional time to perform
any final tasks, you can request additional execution time from the
system by calling beginBackgroundTaskWithExpirationHandler:. In
practice, you should return from applicationDidEnterBackground: as
quickly as possible. If the method does not return before time runs
out your application is terminated and purged from memory.
You should perform any tasks relating to adjusting your user interface
before this method exits but other tasks (such as saving state) should
be moved to a concurrent dispatch queue or secondary thread as needed.
Because it's likely any background tasks you start in
applicationDidEnterBackground: will not run until after that method
exits, you should request additional background execution time before
starting those tasks. In other words, first call
beginBackgroundTaskWithExpirationHandler: and then run the task on a
dispatch queue or secondary thread.
The application also posts a
UIApplicationDidEnterBackgroundNotification notification around the
same time it calls this method to give interested objects a chance to
respond to the transition.
For more information about how to transition gracefully to the
background, and for information about how to start background tasks at
quit time, see iOS App Programming Guide.
Hope this helps clear the issue for you man.
Adrian
Here is the link to the technical note that is available on developer section. It is dealing with networking and multitasking. The actual method used in this doc deals with only applicationDidEnterBackground and since iOS 5 they have a system called watchdog which terminates the app if the network is unresponsive automatically. Hence there is no need to actually call applicationWillTerminate and try to execute codes to allow your app to finish its task before the app is terminated. The app will enter the background and will continue its task until the last task is completed. I hope that makes sense, but here is the link. Please read the watchdog section.
https://developer.apple.com/library/ios/#technotes/tn2277/_index.html#//apple_ref/doc/uid/DTS40010841
Hope this helps. :)