← Назад к вопросам

Для чего нужно писать weak self в замыканиях?

1.3 Junior🔥 211 комментариев
#Управление памятью

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Для чего нужно писать weak self в замыканиях?

Основная проблема: предотвращение циклических ссылок (Retain Cycles)

Ключевая причина использования weak self (или unowned self) в замыканиях — избежание циклических ссылок (retain cycles) между объектами, что приводит к утечкам памяти (memory leaks). В Swift используется система автоматического подсчета ссылок (ARC), которая управляет памятью объектов. Когда объект захватывается в замыкании, ARC увеличивает его счетчик ссылок. Если этот объект также хранит ссылку на само замыкание, возникает взаимная зависимость, которая может помешать корректному освобождению памяти.

Механизм захвата (capture list) в замыканиях

В Swift замыкания могут захватывать значения из окружающего контекста. Для управления силой ссылок на захваченные значения используется список захвата (capture list) перед параметрами замыкания:

class MyViewController: UIViewController {
    var networkService = NetworkService()
    
    func fetchData() {
        networkService.fetch { [weak self] result in
            // self теперь является Optional (weak reference)
            guard let strongSelf = self else { return }
            strongSelf.updateUI(with: result)
        }
    }
}

Сравнение weak и unowned

  • weak self: создает опциональную слабую ссылку. Если исходный объект (self) уничтожается, weak self автоматически становится nil. Это безопасный вариант, требует проверки (guard let).
  • unowned self: создает неопциональную слабую ссылку. Предполагает, что объект будет существовать на протяжении всей жизни замыкания. Если объект уничтожится раньше, обращение к unowned self приведет к краху (runtime crash).

Практические сценарии использования

1. Замыкания, хранящиеся как свойства (например, completion handlers)

Когда замыкание хранится как свойство класса (например, callback), и внутри этого замыкания используется self, возникает прямая циклическая ссылка:

class DataManager {
    var onDataUpdated: (() -> Void)?
    
    func setupCallback() {
        // ПРОБЛЕМА: strong reference -> retain cycle
        onDataUpdated = {
            self.processData() // self захвачен strongly
        }
    }
    
    // Решение с weak self:
    func setupCallbackCorrectly() {
        onDataUpdated = { [weak self] in
            guard let self = self else { return }
            self.processData()
        }
    }
}

2. Асинхронные операции (Network calls, Animations)

В асинхронных операциях (загрузка данных, анимации) замыкание часто выполняется после того, как вызывающий объект может быть уже уничтожен (например, закрыт ViewController):

class ProfileViewController: UIViewController {
    func loadUserProfile() {
        APIClient.fetchProfile { [weak self] profile in
            // Если пользователь закрыл экран, self будет nil
            guard let self = self else { return }
            self.updateProfileView(profile)
        }
    }
}

3. Использование внутри DispatchQueue или OperationQueue

При диспетчеризации задач в глобальных очередьях, объект может быть уничтожен до выполнения блока:

class TaskScheduler {
    func scheduleBackgroundTask() {
        DispatchQueue.global().async { [weak self] in
            self?.performBackgroundWork() // безопасно, если self уже деаллоцирован
        }
    }
}

Когда НЕ нужно использовать weak self

  • Синхронные и немедленно выполняемые замыкания (например, в методах map, filter массива).
  • Замыкания, которые гарантированно не сохраняются (вызываются и сразу освобождаются).
  • Если объект должен гарантированно существовать до выполнения замыкания (например, в deinit), можно использовать unowned, но с осторожностью.

Итог

weak self — это инструмент проактивного управления памятью в Swift, который предотвращает утечки памяти в сценариях, где замыкания:

  1. Асинхронно выполняются после возможного освобождения объекта.
  2. Сохраняются как свойства, создавая потенциальные циклические ссылки.
  3. Работают в многозадачной среде (GCD, операции).

Использование weak self делает код устойчивым к изменениям жизненного цикла объектов и является стандартной практикой для разработки надежных iOS-приложений.

Для чего нужно писать weak self в замыканиях? | PrepBro