Назад к вопросам
Middle
96
questionbank

Что такое unowned в языке Swift и как он используется?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Unowned reference (слабое косвенное владение) в 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) is being deinitialized")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Unowned ссылка на Customer

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

    deinit {
        print("Card #\(number) is being deinitialized")
    }
}

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) is being deinitialized")
    }
}

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

// Присвоение nil освободит HTMLElement, так как замыкание не удерживает его сильно
paragraph = nil

Выбор между unowned и weak зависит от того, может ли ссылка быть nil в процессе жизни объекта. Если ссылка никогда не может стать nil до освобождения объекта, используйте unowned. Если может - используйте weak.