As stated in the title.
I am running the following code. Each time I perform an API call, I create a new instance of URLSession and use a background-configured session to allow background API calls. ` Code being executed:
import Foundation
// Model definitions struct RandomUserResponse: Codable { let results: [RandomUser] }
struct RandomUser: Codable { let name: Name let email: String }
struct Name: Codable { let first: String let last: String }
// Fetcher class class RandomUserFetcher: NSObject, URLSessionDataDelegate { private var receivedData = Data() private var completion: ((RandomUser?) -> Void)? private var session: URLSession!
func fetchRandomUserInBackground(completion: @escaping (RandomUser?) -> Void) {
self.completion = completion
let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.randomuser.bg")
session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let url = URL(string: "https://randomuser.me/api/" )!
let task = session.dataTask(with: url)
task.resume()
}
// Data received
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
receivedData.append(data)
}
// Completion
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
defer { self.session.finishTasksAndInvalidate() }
guard error == nil else {
print("Error: \(error!)")
completion?(nil)
return
}
do {
let response = try JSONDecoder().decode(RandomUserResponse.self, from: receivedData)
completion?(response.results.first)
} catch {
print("Decoding error: \(error)")
completion?(nil)
}
}
}`
Called in viewDidLoad, etc.:
let fetcher = RandomUserFetcher()
fetcher.fetchRandomUserInBackground { user in
if let user = user {
print("Name: \(user.name.first) \(user.name.last), Email: \(user.email)")
} else {
print("Failed to fetch random user.")
}
}
In Instruments' Network instrument, I focus on my app's process, use 'Command + 3', and switch to 'List: URLSessionTasks'.
Even though didCompleteWithError is called and the API call fully completes, the Duration keeps increasing, and the Success column remains '-' (neither 'Yes' nor 'No').
For non-background URLSessions, the session shows up as 'unnamed session', but for background URLSessions, it appears as 'unnamed background session 1 (XXXXXX-XXXXXX-XXXXX)'.
Does this mean the session is not actually being completed? I've checked Debug Memory Graph and confirmed there is no NSURLSession memory leak, but is it possible that the app is somehow still retaining session information internally?
I also suspect that Instruments may not be able to fully track background URLSession tasks.
Each time I perform an API call, I create a new instance of URLSession
That’s not good. Session objects are fairly heavyweight, and you should not be creating a session per network request. Background sessions objects are significantly heavier than standard session objects, and creating a background session per request is seriously suboptimal.
I recommend that you change your code to share the session between all similar network requests. In many cases you can get away with having a single session object that lives for the entire lifetime of your app.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"