Well, almost. Now, for the important part. You now call registerBackgroundTask when calculations begin so you can continue calculating numbers in the background. This is also why you need backgroundTask. Replace the final line, resultsLabel. You update the label only when the app is active. When the app moves to the background, you print a message to the console instead, stating the new result and how much background time remains.
Tap Play and you should see the app calculating the values. You should see the app still updating the numbers while the time remaining goes down. If you wait for the time to expire when you reach five seconds it could be another value depending on your specific conditions , iOS invokes the expiration block and your app should stop generating output.
Then, if you go back to the app, the timer should start firing again and the whole madness will continue. Suppose you background the app and wait until the allotted time expires. In this case, your app will call the expiration handler and invoke endBackgroundTask , thus ending the need for background time. If you then return to the app, the timer will continue to fire. Because nowhere between the expiration and returning to the background did the app call beginBackgroundTask expirationHandler:.
How can you solve this? There are a number of ways to go about it and one of them is to use a state change notification. You only need to reinstate if there is a timer running and the background task is invalid. Breaking your code into smaller utility functions that do one thing is paying off. In this case you simply need to call registerBackgroundTask. This tells iOS to call your new method reinstateBackgroundTask whenever the application becomes active. Whenever you subscribe to a notification, you should also think about where to unsubscribe.
Use deinit to do this. Add the following:. Background fetch is a mode introduced in iOS 7 that lets your app appear always up-to-date with the latest information while minimizing the impact on battery life. Suppose, for example, you were implementing a news feed in your app. The problem with this solution is that your users are looking at old data for at least several seconds until the new data comes in.
This is what background fetch gives you. When enabled, the system uses usage patterns to determine when to best fire off a background fetch. The system decides the best time to issue a background fetch and for this reason you should not use it to do critical updates.
As the name implies, background fetch normally involves fetching information from an external source like a network service. In contrast to finite-length tasks, you only have seconds to operate when doing a background fetch — the consensus figure is a maximum of 30 seconds, but shorter is better. Time to get started.
First, open FetchViewController. Since it might take several seconds to fetch and parse the data, you pass a completion handler that you call when the process finishes. The guard statement around updateLabel is to ensure that the view is actually loaded. Finally, when the users taps Update , it performs a fetch and, in its completion handler, updates the UI. The first step to enabling background fetching is to check Background fetch in the Capabilities tab of your app.
By now, this should be old hat. Go ahead and do this. Next, open AppDelegate. This requests background fetches by setting the minimum background fetch interval. The default interval is UIApplicationBackgroundFetchIntervalNever , which you might want to switch back to, if, for example, your user logs out and no longer needs updates. You can also set a specific interval in seconds. The system will wait at least that many seconds before issuing a background fetch. Be careful not to set the value too small because it may chew through battery unnecessarily as well as hammer your server.
In the end, the exact timing of the fetch is up to the system but will wait at least this interval before performing it. Add that now to AppDelegate :. For simplicity, this tutorial always specifies. How can I solve it? I use this code to download:. Go to Solution. I have new information regarding my question. On what do you run the code on a real device or on the Xcode simulator? I've always tested on a real device and was getting this issue. I decided to test it on the simulator and was very surprised that the download works fine on it.
I also noticed that when I run the code on a real device - I get this issue, but if I then click to download another file, then I'll see that the first file is immediately downloaded, as if it had already been downloaded, but the completion handler didn't work.
What could be the issue? Why does it work fine on the simulator? This issue happens only in case when device connected to the PC Xcode , when I run app without connection to the PC the download works fine. View solution in original post. Thanks for the report. Also, when you say "the download stops", do you get any error or output? And, do you get any result when you return to the app? I use 6. No, I don't get any error. When I return to the app I see that download isn't complete.
If you look at my code you'll see that I have completion handler which works when dowload is complete, and after return to the app I see that it didn't work. Also in the downloadFile func I get download progress I didn't include it in the question so as not to complicate. When I start downloading a file and then minimize the application, then I'll see that progress stops and it doesn't start again if I return to the app.
Thanks for the additional information. I just tried reproducing this with the code you provided. While I also see the progress reporting stop when the app is sent to the background, if I then bring it back to the foreground the download does then resume and complete. Can you let me know how long you're leaving the app in the background before resuming it? As a good replacement of the Xcode debugger, you can make use of OSLog. While keeping the Console app open, you can start running URLSession upload tasks and move your app into the background.
The more detailed your logging implementation is, the easier it will debug flaws in your uploading logic. This gets me to the next point:. This delay in resuming your app likely enlarges when requesting more and more uploads. Therefore, it might be time-consuming to test your flows. Lastly, your app will only be relaunched after all running background tasks succeed.
How better to end this list with a few tips on speeding up your testing flow for background tasks. We can do this by executing the following piece of code on launch to invalidate our URLSession and its tasks:. Using a custom property to enable background task debugging, we only use this invalidation method when we actually need it.
Waiting for your app to suspend is a waste of time. By using exit 0 we can force our app to suspend:. This will terminate your app, but the system does not interpret this as a force quit. Therefore, your app will relaunch your app in the background when your background session needs attention.
If you like to improve your Swift knowledge, even more, check out the Swift category page. Feel free to contact me or tweet to me on Twitter if you have any additional tips or feedback. Free Swift and iOS related content delivered to you weekly, including both top-writers and lesser-known bloggers from our community. Subscribe now and directly get access to discount on Swift Books and Video Courses! In this article.
0コメント