Основная проблема ARC: цикл сильных ссылок
👋 В предыдущих постах мы уже рассматривали механизм ARC и то, как он работает на практике. Казалось бы, какие могут быть здесь проблемы?
⚠️ Однако существует риск написать код, в котором экземпляр класса никогда не достигнет состояния, когда у него не останется сильных ссылок. Это может произойти, если два экземпляра будут содержать сильные ссылки друг на друга, и каждый из них будет поддерживать работу другого. Такая известная проблема называется циклом сильных ссылок.
👉 Прежде чем перейти к обсуждению решения этой проблемы, я хочу показать на примере, как именно она возникает.
🚘 Возьмем класс Car и добавим к нему еще одно опциональное свойство owner — владельца машины.
class Car { let brand: String var owner: Owner? init(brand: String) { self.brand = brand print("\(brand) is being initialized") } deinit { print("\(brand) is being deinitialized") } }
😎 Также создадим класс Owner с опциональным свойством car:
class Owner { let name: String var car: Car? init(name: String) { self.name = name print("\(name) is being initialized") } deinit { print("\(name) is being deinitialized") } }
🔷 Каждый экземпляр Car обладает свойством brand типа String и опциональным свойством owner. Это означает, что машина может не иметь владельца, и свойство owner является необязательным.
🔶 Аналогично, класс Owner имеет свойство name типа String и опциональное свойство car, поскольку у владельца может не быть автомобиля.
2️⃣ В обоих классах я добавил функции print, чтобы можно было отслеживать создание и освобождение объектов из памяти.
2️⃣ Теперь определим две переменные класса опционального типа:
var volvo: Car? var artem: Owner?
🔷 Затем создадим конкретные экземпляры:
volvo = Car(brand: "Volvo") artem = Owner(name: "Artem")
🔗 У двух созданных объектов по одной ссылке.
✨ Теперь присвоим объекту volvo хозяина artem, а у artem укажем машину volvo:
volvo?.owner = artem artem?.car = volvo
🔗 Теперь у объектов по две ссылки.
🔶 Давайте освободим экземпляры из памяти и посмотрим, что произойдет:
volvo = nil artem = nil
🔷 После запуска программы мы увидим следующее:
Volvo is being initialized Artem is being initialized
То есть ни один из деинициализаторов не был вызван, хотя для экземпляров мы установили значение nil.
🔗 Это означает, что у объектов осталось по одной ссылке, и после освобождения эти экземпляры никуда не делись.
Цикл сильных ссылок препятствует освобождению экземпляров, что приводит к утечке памяти в приложении.
👀 Это одна из проблем, с которыми сталкиваются программисты при использовании механизма ARC. Чтобы избежать подобных утечек памяти, важно внимательно следить за его работой.
❤️ В следующих публикациях я расскажу, как это сделать. Ставьте лайк, если хотите, чтобы посты выходили быстрее.