Sobes.tech
Middle

Capture ro'yxatida doimo weak yoki unowned ishlatish kerakmi?

sobes.tech AI

AIdan javob

Ha, har doim emas.

Retain cycle'larni oldini olish uchun Capture List'da weak yoki unowned ishlatiladi.

Retain cycle, ikki yoki undan ortiq obyekt bir-biriga kuchli ravishda murojaat qilganda yuzaga keladi va bu xotira bo'shatilishini to'xtatadi.

weak yoki unowned ishlatish kerak bo'lsa, agar closure kuchli ravishda self (yoki boshqa bir o'zgaruvchi) ga murojaat qilsa, va self (yoki boshqa obyekt) bu closurega kuchli murojaatga ega bo'lsa.

Bunday holatlar uchun misollar:

  • Asinxron operatsiyalar (tarmoq so'rovlar, ma'lumotlarni qayta ishlash)
  • Observer naqsh
  • Animatsiya bloklari
  • Dispatch navbatlari

Agar closure self (yoki boshqa o'zgaruvchi) ni tutmasa (yoki strukturaviy turlar/enumeratsiyalarni tutsa), weak yoki unowned ishlatish shart emas.

weak va unowned o'rtasidagi farqlar:

Tur Tavsifi Qachon ishlatiladi
weak Zaif (ixtiyoriy) murojaat. nil bo'lishi mumkin. Agar closure ning hayot aylanishi, tutib olgan obyektning hayot aylanishidan qisqa yoki unga teng bo'lsa va obyekt nil bo'lishi mumkin bo'lsa.
unowned Noto'g'ri ixtiyoriy murojaat. nil bo'lmaydi. Agar closure ning hayot aylanishi, tutib olgan obyektning hayot aylanishidan qisqa yoki unga teng bo'lsa va obyekt, closure tugashiga qadar mavjud bo'lishi kafolatlangan bo'lsa. Agar obyekt closuredan oldin ozod qilinsa, crash yuz beradi (unowned murojaati bilan deallocatsiya qilingan instance).

weak ishlatish misoli:

class MyClass {
    var name: String = "Test"

    func performAsyncOperation() {
        // Closure `self` ni tutadi.
        // MyClass, asinxron operatsiya tugashidan oldin ozod qilinishi mumkin.
        DispatchQueue.global().async { [weak self] in
            guard let self = self else {
                // `self` ozod qilindi, chiqamiz
                return
            }
            print("Operatsiya tugadi uchun \(self.name)")
        }
    }

    deinit {
        print("MyClass deallocated")
    }
}

unowned ishlatish misoli:

class ViewController {
    var dismissButton: UIButton!

    func setupButton() {
        dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)

        // Closure `self` ni tutadi.
        // Faraz qilamiz, `self` (ViewController) uzoqroq yoki kamida turgan.
        // Bu holatda, target-action closure emas, balki `unowned` konseptini kuchli referans tsikllarida ko'rsatadi.
        // Agar bu *bir* closure bo'lsa, masalan, UIControl.Event handlerida,
        // va ViewController, tugma bosilishi davomida mavjud bo'lsa:
        // dismissButton.addAction(UIAction { [unowned self] _ in
        //     self.dismiss(animated: true, completion: nil)
        // }, for: .touchUpInside)
    }

    @objc func dismiss() {
        // ViewController ni yopish
    }
}

Agar closure retain cycle yaratmasa, weak yoki unowned ishlatish shart emas va hatto keraksiz tekshiruvlarga olib kelishi mumkin (weak) yoki crashlarga (unowned).

Masalan, self yoki boshqa ob'ektni tutmaydigan va kuchli murojaatga ega bo'lgan closure:

func fetchData(completion: @escaping (Data) -> Void) {
    URLSession.shared.dataTask(with: URL(string: "...")!) { data, response, error in
        guard let data = data else { return }
        // Bu yerda `self` yoki boshqa ob'ektlar tutilmaydi, bu retain cycle'ni yuzaga keltirmaydi.
        completion(data)
    }.resume()
}

Bu holatda, [weak self] yoki [unowned self] kerak emas.