[英]Is [Weak self] always needed when dealing with URLSession?
我無法弄清楚在這種情況下我是否需要使用[weak self]
?
HTTPClient.swift:
struct HTTPClient {
let session = URLSession.shared
func get(url: URL, completion: @escaping (Data) -> Void) {
session.dataTask(with: url) { data, urlResponse, error in
completion(data) // assume everything will go well
}.resume()
}
}
Service.swift
struct Service {
let httpClient: HTTPClient
init(httpClient: HTTPClient = HTTPClient()) {
self.httpClient = httpClient
}
func fetchUser(completion: @escaping (User) -> Void) {
httpClient.get("urlToGetUser") { data in
// transform data to User
completion(user)
}
}
}
ViewModel.swift
class ViewModel {
let service: Service
let user: User?
var didLoadData: ((User) -> Void)?
init(service: Service) {
self.service = service
loadUser()
}
func loadUser() {
service.fetchUser { [weak self] user in // is [weak self] really needed ?
self?.user = user
self?.didLoadData?(user)
}
}
}
這是真的需要用戶[weak self]
嗎? 當我們處理一個我們不知道閉包發生了什么的API時,是否有一條關於如何檢查是否需要的規則? 或者那沒關系(由我們來決定)?
在你給出的例子中, [weak self]
可能是不必要的。 這取決於在請求完成之前釋放ViewModel
您想要發生什么。
正如URLSessionDataTask
docs(強調我的)中所述:
創建任務后,通過調用resume()方法啟動它。 然后會話保持對任務的強引用, 直到請求完成或失敗 ; 您不需要維護對任務的引用,除非它對您的應用程序的內部簿記有用。
會議強烈提到了這項任務。 該任務強烈提到了關閉。 閉包具有對ViewModel
的強引用。 只要ViewModel
沒有對該任務的強引用(它不在您提供的代碼中),那么就沒有循環。
問題是您是否要確保ViewModel
繼續存在足夠長的時間以便執行閉包。 如果您(或不關心),那么您可以使用簡單的強引用。 如果要阻止任務使ViewModel
保持活動狀態,則應使用弱引用。
這就是您需要考慮參考周期的方法。 沒有一般規則“在這里使用weak
”。 當你的意思是什么時,你會使用weak
; 當你不希望這個閉包在self
被釋放之前保持self
。 如果它創造一個循環,那尤其如此。 但是沒有一般的答案是“這會創造一個循環嗎”。 這取決於哪些部分包含引用。
這也指出了您當前的API設計不盡如人意的地方。 你在init
傳遞didLoadData
。 這很可能會創建參考周期並強制您的調用者使用weak
。 相反,如果你在loadUser()
上使didLoadDdata
成為一個完成處理程序,那么你可以避免這個問題並使調用者的生活更輕松。
func loadUser(completion: @escaping ((User?) -> Void)? = nil) {
service.fetchUser {
self?.user = user
didLoadData?(user)
}
}
(你當前的API在任何情況下都有競爭條件。你可以在設置didLoadData
之前啟動loadUser()
。你可能假設在設置dataDidLoad
之前完成處理程序不會完成,但是沒有真正的承諾這可能是真的,但它最多是脆弱的。)
您的代碼的問題不在於使用URLSession,而在於您在視圖控制器中保留了一個函數:
class ViewModel {
var didLoadData: ((User) -> Void)?
}
如果didLoadData
函數隱式或顯式地提到self
(即ViewModel實例),則除非你說weak self
或unowned self
否則你有一個保留周期和內存泄漏。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.