Ҳамеша бояд дар рӯйхати ғуломгирӣ аз weak ё unowned истифода баред?
sobes.tech AI
Ҷавоб аз AI
Не, не винаги.
Използваме weak или unowned в Capture List за предотвратяване на цикли на задържане.
Цикълът на задържане възниква, когато две или повече обекта силно се позовават, пречейки освобождаването на паметта.
Използването на weak или unowned е необходимо, когато затварянето силно се позовава на self (или друга променлива на инстанция на класа/актора), и от своя страна self (или друг обект) има силна референция към това затваряне.
Примери за ситуации, когато е необходимо:
- Асиминрони операции (мрежови заявки, обработка на данни)
- Модел Observer
- Анимационни блокове
- Dispatch опашки
Ако затварянето не улавя self (или друга променлива на класа/актора, която има силна референция към затварянето), или улавя структурни типове/енумерации, използването на weak или unowned не е необходимо.
Разликата между weak и unowned:
| Тип | Описание | Кога да използвате |
|---|---|---|
weak |
Слаба (опционална) референция. Може да стане nil. |
Когато е жизненият цикъл на затварянето по-кратък или равен на този на обекта, който се улавя, и обектът може да стане nil преди завършването на затварянето. |
unowned |
Неосновна (неопционална) референция. Не може да стане nil. |
Когато е жизненият цикъл на затварянето по-кратък или равен на този на обекта, който се улавя, и гарантирано че обектът ще съществува до завършването на затварянето. Ако обектът бъде освободен преди изпълнението на затварянето, ще настъпи срив (unowned референция към деактивирана инстанция). |
Пример за използване на weak в Capture List:
class MyClass {
var name: String = "Test"
func performAsyncOperation() {
DispatchQueue.global().async { [weak self] in
guard let self = self else {
return
}
print("Операцията приключи за \(self.name)")
}
}
deinit {
print("MyClass е освободен")
}
}
Пример за използване на unowned в Capture List:
class ViewController {
var dismissButton: UIButton!
func setupButton() {
dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
// Този пример показва, че `self` (ViewController) живее по-дълго или толкова дълго, колкото и действието на бутона.
// Target-action не е затваряне, но илюстрира концепцията за unowned при силен цикъл на задържане.
// Ако това беше затваряне, например, в handler-у UIControl.Event,
// и ViewController е гарантирано съществуващ по време на натискането на бутона:
// dismissButton.addAction(UIAction { [unowned self] _ in
// self.dismiss(animated: true, completion: nil)
// }, for: .touchUpInside)
}
@objc func dismiss() {
// Затваряне на view controller
}
}
Ако затварянето не създава цикъл на задържане, използването на weak или unowned не е необходимо и може дори да доведе до ненужни проверки (в случай на weak) или потенциални сривове (в случай на unowned).
Например, затваряне, което не улавя self или друг обект, който има силна референция към затварянето:
func fetchData(completion: @escaping (Data) -> Void) {
URLSession.shared.dataTask(with: URL(string: "...")!) { data, response, error in
guard let data = data else { return }
// Тук няма улавяне на `self` или други обекти, които биха могли да причинят цикъл на задържане.
completion(data)
}.resume()
}
В този случай [weak self] или [unowned self] в Capture List не са необходими.