Stop app from refreshing when going into background. (iOS)
makeUIView
is called to create the view.updateUIView
is called multiple times to update the view
So anything you want to do just once, do it in the makeUIView
Move the code from updateUIView
to makeUIView
and check if things work as expected.
swift/ios refreshing app data when in background
Use iOS Background Fetch feature where you can specify minimum background fetch interval. But actual interval between successive invocation of your code will be determined by iOS framework. For details checkout this link: http://code.tutsplus.com/tutorials/ios-7-sdk-working-with-background-fetch--mobile-20520
I use this approach in my app and I think it is a preferred way of doing.
Does background app refresh have an effect on a background URLSession?
I finally found an answer to this problem. Posting it here for anyone having the same issue.
Thanks to this thread, see Quinn's response below :
iOS 13 introduces new behaviour (r. 47718087) whereby, if the user has turned Background App Refresh off in Settings — either globally or for your app, assuming it has this setting — your app won’t be resumed (or relaunched) when the tasks complete in an
NSURLSession
background session. That is, your session will behave as ifsessionSendsLaunchEvents
were set to false.
How to configure Background App Refresh using Swift?
You will need to move your downloading code from the view controller and into another class or at least modify you current background refresh method to instantiate the view controller if required. Background refresh can be triggered when your app hasn't been launched in the foreground, so the if let
will fall through.
Consider the code in your question:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
if let VC = window?.rootViewController as? SearchVC {
// Update JSON data
VC.downloadJSON()
completionHandler(.newData)
}
}
If the if let...
doesn't pass then you exit from the function without calling the completionHandler
, so you get the runtime warning that the completion handler was not called.
You could modify your code to include a call to the completionHandler
in an else
case, but in this case no fetch will have taken place:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
if let VC = window?.rootViewController as? SearchVC {
// Update JSON data
VC.downloadJSON()
completionHandler(.newData)
} else {
completionHandler(.noData)
}
Or you could instantiate the view controller (or I would suggest another data fetching class) if required:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
let vc = (window?.rootViewController as? SearchVC) ?? SearchVC()
// Update JSON data
vc.downloadJSON()
completionHandler(.newData)
}
You should also modify your downloadJSON
function to include a completion handler argument, which you invoke when the JSON download is complete. This will let you call the background fetch completion handler once you have actually downloaded the data:
func downloadJSON(completion: ((Bool,Error?) -> Void )? = nil)) {
guard let url = URL(string: "myURL") else {
completion?(false, nil)
return
}
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard nil == err else {
completion?(false, err)
return
}
guard let data = data else {
completion?(false, nil)
return
}
do {
let downloadedCurrencies = try JSONDecoder().decode([Currency].self, from: data)
// Adding downloaded data into Local Array
Currencies = downloadedCurrencies
completion(true,nil)
} catch let jsonErr {
print("Here! Error serializing json", jsonErr)
completion?(false,jsonErr)
}
}.resume()
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
let vc = (window?.rootViewController as? SearchVC) ?? SearchVC()
// Update JSON data
vc.downloadJSON() { (newData,error) in
if let err = error {
NSLog("Background fetch error: \(err.localizedDescription)")
completionHandler(.fail)
} else {
completionHandler(newData ? .newData:.noData)
}
}
}
Update September 2019
Note that iOS 13 introduces new background fetch and processing functionality. Refer to this WWDC session for more details
Related Topics
Checkbox Uitableview with Different Sections
Sorting Struct Array in Swift 4
Updating Label Takes Too Long (Swift)
iOS Firebase Database Get Key of Value
Why Is My Admob Interstitial Working Fine in Xcode Simulator But Not on My Test Devices
Modeling Sub-Collections in Mongodb Realm Sync
Nsclassfromstring Returning Nil for Nested Class
Could Not Cast Value of Type 'Nsnull' (0X10Aa1B600) to 'Nsstring' (0X10B4Dab48)
Swift 2 Cannot Invoke 'Fseventstreamcreate' with an Argument List of Type
Save Uiimage Array in Nsuserdefaults
Save Struct in Class to Nsuserdefaults Using Swift
Cgaffinetransform -How to Align Video in Screen Center
How to Find the Index of a Tuple Element from an Tuple Array? iOS, Swift
Cannot Invoke 'Decode' with an Argument List of Type '(T, From: Data)'