Sobes.tech
Middle

чӣ аст unowned дар забони Swift ва чӣ гуна истифода мешавад?

sobes.tech AI

Ҷавоб аз AI

Референция без собственост (слабо косвено владение) в Swift се използва за избягване на цикли на силно владение (retain cycles), когато два обекта силно се позовават един на друг, предотвратявайки тяхното освобождаване от паметта.

Характеристики на unowned:

  • Гарантира, че обектът, към който се отнася unowned препратката, винаги съществува до момента на използването ѝ.
  • Ако се опитате да получите достъп до unowned препратка след като свързаният обект е освободен, ще настъпи грешка в изпълнение (runtime crash).
  • Използва се, когато жизненият цикъл на рефериращия обект не е по-дълъг от този на обекта, към който се отнася. Тоест, unowned препратката не прави обекта по-силен.

Пример за използване в захват на затваряне:

class Customer {
    let name: String
    var card: CreditCard?

    init(name: String) {
        self.name = name
    }

    deinit {
        print("\(name) се освобождава")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Unowned препратка към Customer

    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }

    deinit {
        print("Карта #\(number) се освобождава")
    }
}

var john: Customer? // Опционален Customer за възможност за освобождаване
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

// Присвояване на nil към john ще доведе до освобождаване на Customer и Card,
// тъй като няма цикъл на силно владение
john = nil 

Друг пример - използване на unowned в списък за захват на затваряне:

class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = { [unowned self] in // Използване на unowned self
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) се освобождава")
    }
}

var paragraph: HTMLElement? // Опционален HTML елемент
paragraph = HTMLElement(name: "p", text: "hello world")
print(paragraph!.asHTML())

// Присвояване на nil ще освободи HTMLElement, тъй като затварянето не държи го силно
paragraph = nil

Изборът между unowned и weak зависи от това дали препратката може да бъде nil по време на живота на обекта. Ако препратката никога не може да стане nil преди освобождаването на обекта, използвайте unowned. Ако може - използвайте weak.