TGViewer
Мобильный трудоголик Мобильный трудоголик @hardworkerit · 1.64K subscribers
Post #487 450
🔢 Swift 6.4: новая диагностика ретейн циклов.

В Swift 6.4 появилась новая диагностика, которая помогает ловить неочевидные ретейн циклы. Предупреждение срабатывает, когда вложенное замыкание выполняет слабый захват, а родительское замыкание при этом неявно захватывает объект как сильную ссылку.

На первый взгляд это может показаться избыточным. Зачем указывать слабый захват дважды? Но на практике это очень полезное предупреждение, которое помогает избежать распространенного типа ошибок управления памятью.


В чем суть проблемы:

Рассмотрим пример. Внутри замыкания, переданного в loadNearbyFriends, используется weak self. При этом родительское замыкание не захватывает self явно.


timer = Timer.scheduledTimer(
withTimeInterval: 3,
repeats: true,
block: { [service] _ in
service.loadNearbyFriends { [weak self] friends in
self?.friends = friends
}
}
)


При компиляции в Swift 6.3 это код не вызывает предупреждений. Но на самом деле здесь возникает ретейн цикл. Хотя мы не захватывали self явно, компилятор неявно вставляет сильный захват self в родительское замыкание.

В результате Timer захватывает self, который удерживает объект через свойство timer. Классический ретейн цикл.


Что изменилось в Swift 6.4:

Теперь при компиляции этого кода появляется предупреждение:

'weak' ownership of capture 'self' differs from implicitly-captured strong reference in outer scope


Предупреждение явно указывает на проблему. И это гораздо лучше, чем молчаливый ретейн цикл, который может привести к утечке памяти.


Как исправить:

Есть несколько способов:

🔹Переместить weak self в родительское замыкание. Это работает, если self не используется во внешнем замыкании.


block: { [weak self, service] _ in
service.loadNearbyFriends { friends in
self?.friends = friends
}
}


🔹Выполнить два отдельных weak self захвата. Это подходит, если внешнее замыкание действительно использует self.


block: { [weak self] _ in
guard let self else { return }
logScanningDidStart()
service.loadNearbyFriends { [weak self] friends in
self?.friends = friends
}
}


🔹Явно добавить self в список захвата родительского замыкания, если сильный захват не приводит к ретейн циклу. Например, при создании Task.


Task { [self] in
guard await !cache.isValid else { return }
service.loadNearbyFriends { [weak self] friends in
self?.friends = friends
}
}


В этом случае сильный захват безопасен, потому что после проверки кеша и вызова loadNearbyFriends замыкание будет освобождено.


🔗 Читать подробнее


💡 Вывод:

Swift 6.4 добавляет предупреждение для слабого захвата во вложенных замыканиях, когда родительское замыкание неявно захватывает объект как сильную ссылку.

Это помогает ловить неочевидные ретейн циклы, которые раньше оставались незамеченными. Диагностика требует большей явности в коде, но это оправдано. Ретейн циклы - слишком частая проблема, чтобы оставлять их без внимания.

Swift продолжает развиваться в сторону безопасности. Новые предупреждения помогают писать более надежный код и избегать типичных ошибок.


Подписаться на канал:
➡️ Telegram | Max
  • 👍 7
  • ❤ 3
  • 🔥 2
  • 👀 1
More from @hardworkerit
  1. Oct 4, 2026🔢 SwiftUI: определение угла раскрытия iPhone Duo. В iOS 27.1 появился модификатор .onHing…
  2. Oct 2, 2026👣 Архитекторы, тестировщики и кодеры. Создаем мультиагентную команду Разработка с ИИ-аген…
  3. Oct 1, 2026🔢 Работа с Picture-in-Picture в iOS. Picture-in-Picture - системная функция iOS, которая…
  4. Sep 29, 2026🔢 Управление тулбарами на iPhone Duo. На iPhone Duo элементы управления навигацией, дейст…
  5. Sep 27, 2026🔢 Новые возможности Hashable в Swift 6.4 В Swift 6.4 добавили Hashable для нескольких тип…
  6. Sep 25, 2026🔢 Приватные свойства больше не ломают memberwise инициализатор в Swift 6.4 Swift автомати…
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 →