Search code examples
swift

Reference count mechanism in Swift makes me confused


In Swift, when the Retain value becomes 0, it is deleted from memory. Therefore, dataTask() in the example below must also stop execution when the foo() function ends. This is because the job variable is a local variable, not a global variable.

But this code runs fine. completionHandler is called even if the foo() function terminates. How is this possible? Am I missing something?

func foo() {
    let job = URLSession.share.dataTask(with: url) { _, _, _ in
        // completionHandler is called, but I don't know why
    }
}

Solution

  • The code you posted without job.resume() will not call a completionHandler no matter what (i.e. not even related to memory management, the task will simply not run).

    But if we correct your code to:

    func foo(url: URL) {
        let job = URLSession.shared.dataTask(with: url) { _, _, _ in
            // ...
        }
        job.resume()
    }
    

    Then indeed, the task will run even though the function completed, and no apparent reference to the task exists. This is unfortunately not mentioned in most of the pages of their docs, but it is explained on this page:

    After you create a task, you start it by calling its resume method. The session then maintains a strong reference to the task until the request finishes or fails; you don’t need to maintain a reference to the task unless it’s useful for your app’s internal bookkeeping.

    So in other words, when you call job.resume(), the URLSession.shared will start maintaining the strong reference to the URLSessionDataTask object, and thus task won't get evicted.