Sobes.tech
Middle

Ամեն դեպքում անհրաժեշտ է օգտագործել weak կամ unowned բռնագրավման ցանկում:

sobes.tech AI

Պատասխան AI-ից

Ոչ, ոչ միշտ։

Օգտագործում ենք weak կամ unowned Capture List-ում՝ կանխելու համար retain cycle-երը։

Retain cycle-երը առաջանում են, երբ երկու կամ ավելի օբյեկտներ ուժեղորեն հղում են միմյանց, ինչը չի թույլատրում հիշողությունը ազատել։

Օգտագործել weak կամ unowned անհրաժեշտ է, երբ կարճաժամկետ փակումը ուժեղորեն հղում է self (կամ այլ դասի/ակտորի օրինակային փոփոխական), և իր հերթին self (կամ այլ օբյեկտ) ունի ուժեղ հղում այդ փակմանը։

Նմուշներ իրավիճակների, երբ դա անհրաժեշտ է՝

  • Ասինխրոն օպերացիաներ (սնետվերային հարցումներ, տվյալների մշակում)
  • Observer պաթերն
  • Անիմացիոն բլոկներ
  • Dispatch հերթեր

Եթե փակումը չի բռնում self-ին (կամ այլ դասի/ակտորի փոփոխական, որը ունի ուժեղ հղում փակմանը), կամ բռնում է կառուցվածքային տիպեր/համարներ, weak կամ unowned օգտագործելը անհրաժեշտ չէ։

weak և unowned միջև տարբերությունը՝

Տիպ Նկարագրություն Երբ օգտագործել
weak Թույլ (ընտրական) հղում։ Կարող է դառնալ nil։ Երբ փակման կյանքի ցիկլը կարճ է կամ հավասար է բռնված օբյեկտի կյանքի ցիկլին, և օբյեկտը կարող է դառնալ nil մինչև փակման ավարտը։
unowned Անվճար (չընտրական) հղում։ Չի կարող դառնալ nil։ Երբ փակման կյանքի ցիկլը կարճ է կամ հավասար է բռնված օբյեկտի կյանքի ցիկլին, և հաստատապես հստակ է, որ օբյեկտը գոյություն կունենա մինչև փակման ավարտը։ Եթե օբյեկտը ազատվի մինչև փակման կատարմանը, տեղի կունենա խափանում (unowned հղում deallocated instance-ին):

Օրինակ weak օգտագործման՝

class MyClass {
    var name: String = "Test"

    func performAsyncOperation() {
        DispatchQueue.global().async { [weak self] in
            guard let self = self else {
                return
            }
            print("Operation completed for \(self.name)")
        }
    }

    deinit {
        print("MyClass deallocated")
    }
}

Օրինակ unowned օգտագործման՝

class ViewController {
    var dismissButton: UIButton!

    func setupButton() {
        dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
        // Այս դեպքում, փակումը բռնում է `self`-ին։
        // Եթե դա լիներ փակում, օրինակ, UIControl.Event-ի մշակողում,
        // և ViewController-ը հաստատ գոյություն կունենա մինչև կոճակի սեղմումը՝
        // dismissButton.addAction(UIAction { [unowned self] _ in
        //     self.dismiss(animated: true, completion: nil)
        // }, for: .touchUpInside)
    }

    @objc func dismiss() {
        // Դիսմիս տեսքի կառավարման համար
    }
}

Եթե փակումը չի ստեղծում retain cycle, 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` կամ այլ օբյեկտների բռնում, որոնք կարող են առաջացնել retain cycle։
        completion(data)
    }.resume()
}

Այս դեպքում [weak self] կամ [unowned self] օգտագործելը անհրաժեշտ չէ։