Память
October 21

Разрешение цикла сильных ссылок с помощью unowned ссылки

👋 Для разрешения цикла сильных ссылок мы разбирали использование слабых (weak) ссылок. В этом посте мне хотелось бы сосредоточиться на unowned ссылках и их применении.

😁 Стоит отметить, что weak ссылки на русский переводятся однозначно как «слабые». Однако unowned ссылки имеют множество переводов: бесхозные, непривязанные, не принадлежащие и другие. Напишите в комментариях, какой из этих вариантов вам больше по душе!

Что такое unowned ссылка?

🔗 Unowned ссылка представляет собой особый тип ссылки, который не увеличивает счетчик ссылок на объект, что позволяет избежать цикла сильных ссылок.

🔖 В отличие от weak ссылок, unowned ссылки предполагают, что объект, на который они ссылаются, будет существовать на момент обращения к этой ссылке.

⚠️ Важно понимать, что если объект, на который указывает unowned ссылка, был освобожден, приложение вызовет ошибку во время выполнения (runtime error).

Пример использования unowned ссылки

📚 Применение unowned ссылок аналогично тому, как мы работаем со слабыми ссылками.

👤 Давайте создадим класс Customer, в котором будет опциональное свойство car, поскольку у покупателя может и не быть машины.

class Customer {
    let name: String
    var car: Car?
    
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    
    deinit {
        print("\(name) is being deinitialized")
    }
}

🚘 Теперь создадим класс Car, который будет содержать обязательное поле Customer, так как у каждой машины, по нашим предположениям, должен быть покупатель.

class Car {
    let brand: String
    unowned let customer: Customer
    
    init(brand: String, customer: Customer) {
        self.brand = brand
        self.customer = customer
        print("\(brand) is being initialized")
    }
    
    deinit {
        print("\(brand) is being deinitialized")
    }
}

👉 Как видно, перед let customer мы добавили слово unowned, что указывает на то, что никто не владеет этой ссылкой, тем самым избегая цикла сильных ссылок.

🔷 Теперь создадим клиента для автомобиля.

var mark: Customer?

🔶 Создадим экземпляр Customer и используем его для инициализации и назначения нового экземпляра Car в качестве свойства машины.

mark = Customer(name: "Mark")
mark?.car = Car(brand: "Kia", customer: mark!)

🔷 В этом случае экземпляр Customer получает сильную ссылку на экземпляр Car, а экземпляр Car имеет unowned ссылку на экземпляр Customer.

🔶 Если мы присвоим объекту mark значение nil, то не останется сильных ссылок на экземпляр Customer:

mark = nil

🔷 После этого больше не будет сильных ссылок на экземпляр Car, и он также будет освобожден.

🔶 В результате выполнения кода мы увидим следующий вывод:

Mark is being initialized
Kia is being initialized
Mark is being deinitialized
Kia is being deinitialized

⚠️ Здесь важно учитывать контекст, в котором вы работаете, и быть уверенным в том, что объект будет доступен на момент обращения через unowned ссылку.

✍️ Напишите, пожалуйста, в комментариях, как часто и в каких случаях вы видели использование unowned ссылки в коммерческих приложениях.