На каком потоке вызывается deinit в Swift?

«На каком потоке вызывается deinit в Swift?» — вопрос из категории Управление памятью, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Метод deinit вызывается на том же потоке, где была удалена последняя сильная ссылка на объект. Это поведение не гарантируется системой и зависит от контекста использования объекта.

Пример:

class MyClass {
    deinit {
        print("Deinit on thread: (Thread.current)")
    }
}

DispatchQueue.global().async {
    let object = MyClass() // Создание в фоновом потоке
    // object выходит из области видимости здесь
    // deinit будет вызван в этом же фоновом потоке
}

Важные нюансы:

  1. Нет гарантии немедленного вызова: deinit может быть вызван не сразу после выхода объекта из области видимости, а позже, когда сработает сборщик мусора (ARC).
  2. Циклические ссылки: Если объект участвует в цикле сильных ссылок (strong reference cycle), deinit не будет вызван никогда, что приводит к утечке памяти.
  3. Опасность deadlock: Внутри deinit следует избегать синхронных вызовов (sync) на текущий поток, так как это может привести к взаимной блокировке.
  4. Работа с потокобезопасностью: Поскольку поток вызова неизвестен заранее, любой доступ к общим ресурсам или UI из deinit должен быть должным образом синхронизирован.