TGViewer
Мобильный трудоголик Мобильный трудоголик @hardworkerit · 1.65K subscribers
Post #125 977
🔢 Retain Cycle в Swift: как не попасть в тонкую ловушку.

Retain cycle — одна из самых коварных проблем в Swift. Даже опытные разработчики могут не заметить, как создают цикл удержания ссылок, который мешает освобождению памяти. Разберём пример, который выглядит безобидно, но содержит скрытую угрозу.


⚠️ Что такое Retain cycle?
Retain Cycle (цикл удержания сильных ссылок) в Swift — это ситуация, когда два или более объекта удерживают друг друга через сильные ссылки (strong), не позволяя ARC (Automatic Reference Counting) освободить память. Это приводит к утечкам памяти, так как объекты никогда не освобождаются.


❌ Проблемный код.


class MyClass {
var task: Task<Void, Never>?

init() {
task = Task { [weak self] in
guard let self else { return }

repeat {
self.performSomeWork() // <- Цикл удержания!
} while !Task.isCancelled
}
}

func performSomeWork() {
}

deinit {
print("deinit") // Не выполнится
task?.cancel()
}
}



🤔 Что не так?
🔸 guard let self создаёт сильную ссылку на весь блок Task.
🔸 Цикл repeat работает бесконечно, удерживая self → deinit никогда не вызовется.


✅ Как исправить?

1️⃣ Изменить область видимости сильной ссылки.
Перенесите guard внутрь цикла, чтобы ссылка освобождалась после каждой итерации:


task = Task { [weak self] in
repeat {
guard let self else { return }
self.performSomeWork() // Сильная ссылка только здесь
} while !Task.isCancelled
}


2️⃣ Использовать слабую ссылку везде.
Если метод не требует обязательного self:


task = Task { [weak self] in
repeat {
self?.performSomeWork() // слабая ссылка
} while !Task.isCancelled
}


3️⃣ Вручную разорвать цикл.
Вызовите cancel() вне deinit, например, при закрытии экрана:


task?.cancel()
task = nil



⚠️ Чего лучше избегать?
Явный захват метода performSomeWork:


task = Task { [performSomeWork] in
repeat {
performSomeWork() // Метод всё равно содержит неявный self
} while !Task.isCancelled
}


Методы экземпляра неявно захватывают self, даже если переданы как замыкание.


🤔 Как отлавливать такие проблемы?
🔸 Тесты: Добавьте проверку на deinit с задержкой.
🔸 Instruments: Используйте Leaks и Allocations для поиска утечки памяти и цикличных ссылок.
🔸 Логирование: Добавьте print в deinit для критичных объектов.


💡 Вывод:
🔹 [weak self] — не панацея. Всегда анализируйте область видимости сильных ссылок.
🔹 Для бесконечных задач (repeat, while) используйте локальный guard или явный cancel.
🔹 Пишите тесты на освобождение памяти — это сэкономит часы отладки.


➡️ Подписаться на канал
Мобильный трудоголик
  • 👍 32
  • 🔥 20
  • ❤ 3
  • 🙏 2
  • 😁 1
More from @hardworkerit
  1. Oct 10, 2026🔢 Переиспользуемые превью в SwiftUI. SwiftUI-превью часто начинаются с простого кода. Но…
  2. Oct 9, 2026👨‍💻 Умение адаптироваться - важный навык айтишника, который часто недооценивают. В ИТ не…
  3. Oct 8, 2026🈸 Apple обяжет разработчиков поддерживать iPhone Duo. Apple опубликовала требования к при…
  4. Oct 6, 2026🔢 Swift 6.4: новая диагностика ретейн циклов. В Swift 6.4 появилась новая диагностика, ко…
  5. Oct 4, 2026🔢 SwiftUI: определение угла раскрытия iPhone Duo. В iOS 27.1 появился модификатор .onHing…
  6. Oct 2, 2026👣 Архитекторы, тестировщики и кодеры. Создаем мультиагентную команду Разработка с ИИ-аген…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →