Retain cycle (цикл удержания) — это ситуация в управляемых языках программирования, таких как Objective-C или Swift (для приложений iOS и macOS), когда два или более объектов ссылается друг на друга, создавая замкнутую сеть ссылок. Это приводит к тому, что объекты не могут быть корректно освобождены из памяти автоматически сборщиком мусора, так как каждый объект все еще имеет на него ссылку. В результате память остается занятой объектами, которые фактически не используются, что может привести к проблемам с утечками памяти и плохой производительности приложения.
Retain cycle обычно возникает, когда два объекта хранят ссылки друг на друга в свойствах с ключевым словом «strong» (Objective-C) или атрибутом @property
с атрибутом retain
или strong
(в Swift). В таких случаях, когда ни один из объектов больше не нужен, они все равно не будут освобождены из памяти, так как каждый объект все еще имеет на него ссылку через другой объект.
Для предотвращения retain cycle в Objective-C можно использовать ключевые слова weak
или unsafe_unretained
, чтобы избежать сильных ссылок, тем самым позволяя объектам быть освобожденными из памяти, когда на них больше нет сильных ссылок. В Swift также можно использовать опциональные типы или слабые ссылки с помощью ключевых слов weak
или unowned
для избежания retain cycle. Важно правильно управлять жизненным циклом объектов и ссылками между ними, чтобы избежать проблем с утечками памяти.
Пример кода с Retain cycle
Вот пример кода на Swift, демонстрирующий создание цикла удержания:
class Person { var name: String var apartment: Apartment? init(name: String) { self.name = name print("\(name) has been initialized") } deinit { print("\(name) has been deinitialized") } } class Apartment { var unit: String weak var tenant: Person? // Используем weak ссылку, чтобы избежать retain cycle init(unit: String) { self.unit = unit print("Apartment \(unit) has been initialized") } deinit { print("Apartment \(unit) has been deinitialized") } } // Создаем экземпляры объектов var john: Person? var unit4A: Apartment? // Инициализируем объекты и создаем retain cycle john = Person(name: "John Doe") unit4A = Apartment(unit: "4A") john?.apartment = unit4A unit4A?.tenant = john // Устанавливаем оба объекта в nil, чтобы увидеть, когда они будут освобождены john = nil unit4A = nil
В этом примере Person
и Apartment
взаимно ссылается друг на друга, что создает цикл удержания. Однако, так как свойство tenant
в классе Apartment
объявлено как weak
, это позволяет объекту Person
быть освобожденным из памяти, когда на него больше нет сильных ссылок. Таким образом, мы избегаем утечки памяти.
Другие вопросы с собеседований →.