Sobes.tech
Middle+

Ҳамеша бояд дар рӯйхати тасвиркунӣ weak ё unowned истифода шавад?

sobes.tech AI

Ҷавоб аз AI

Не, не винаги.

weak и unowned се използват за предотвратяване на силни цикли на препратки (retain cycles) в затварянията, когато затварянето държи силна препратка към обект, а обектът от своя страна държи силна препратка към затварянето.

weak или unowned трябва да се използват, когато затварянето улавя силна препратка към self или друг референтен тип и съществува вероятност да възникне силен цикъл.

Ситуации, когато не е необходимо да се използва weak/unowned:

  • Затварянето улавя стойностни типове (структури, енумуей, кортежи). Те се копират при улавяне и не възникват цикли.
  • Затварянето улавя референтен тип, но няма двупосочен силен цикъл. Например, ако затварянето се създава локално в метод и не се съхранява от обект, към който се отнася.
  • Затварянето има кратък живот и ще бъде изпълнено преди обектът, към който се отнася, да бъде освободен. Например, затваряне, предадено като Completion Handler, което се изпълнява незабавно.

Избор между weak и unowned:

  • weak: използва се, когато уловеният обект може да стане nil по всяко време преди изпълнението на затварянето. Препратката е като опционална (ObjectType?). Изисква се проверка за nil преди използване.
  • unowned: използва се, когато е известно, че уловеният обект винаги ще съществува по време на изпълнение на затварянето. Препратката не е опционална (ObjectType). Не изисква проверка за nil. Използването на unowned за обект, който е станал nil, ще доведе до срив (runtime error).
// Пример, когато не е необходим `weak`/`unowned` (улов на структура)
struct MyStruct {
    var value: Int
}

let myStruct = MyStruct(value: 10)
let closure = {
    print(myStruct.value) // копие на myStruct
}
closure()

// Пример, когато не е необходим `weak`/`unowned` (локално затваряне)
class MyClass {
    func doSomething() {
        let localValue = 5
        let localClosure = {
            print(self.description) // улов на self, но затварянето не се съхранява в MyClass
        }
        localClosure()
    }

    var description: String {
        return "Instance of MyClass"
    }
}

let myObject = MyClass()
myObject.doSomething()

// Пример, когато е необходим `weak` (може да стане `nil`)
class AsyncOperation {
    var completionHandler: (() -> Void)?

    func performOperation() {
        DispatchQueue.global().async {
            print("Operation completed")
            self.completionHandler?()
        }
    }

    deinit {
        print("AsyncOperation deinitialized")
    }
}

class ViewController {
    var op: AsyncOperation?

    func setupOperation() {
        op = AsyncOperation()
        op?.completionHandler = { [weak self] in
            guard let self = self else { return }
            print("Completion handler in ViewController: \(self)")
        }
    }

    deinit {
        print("ViewController deinitialized")
    }
}

// Пример, когато е необходим `unowned` (гарантирано съществува)
class Button {
    var action: (() -> Void)?

    func tap() {
        action?()
    }

    deinit {
        print("Button deinitialized")
    }
}

class ViewControllerWithButton {
    var button: Button

    init() {
        button = Button()
        button.action = { [unowned self] in
            print("Button tapped in ViewControllerWithButton: \(self)")
        }
    }

    deinit {
        print("ViewControllerWithButton deinitialized")
    }
}