MVVM-C с RxSwift: «[weak self]» в закрытии

Я работаю над проектом iOS с RxSwift, и я использую MVVM с шаблоном координаторов.

Вот моя реализация:

ViewModel:

// MARK: - Private

private let showNextViewSubject = PublishSubject<Void>()

// MARK: - Inputs

var showNextView: AnyObserver<Void> {
    return showNextViewSubject.asObserver()
}

// MARK: - Outputs

var didShowNextView: Observable<Void> {
    return showNextViewSubject.asObservable()
}

ViewController:

private func bindButton() {
    _ = button.rx.tap
        .bind(to: viewModel.showNextView)
        .disposed(by: disposeBag)
}

Координатор:

self.viewModel.didShowNextView
        .subscribe(onNext: { [weak self] _ in
            self?.showNextView()
        })
        .disposed(by: disposeBag)

Моя проблема связана с [weak self] _ в координаторе: когда я добавляю его, self?.showNextView() никогда не вызывается, но это хорошо работает, когда я его удаляю.

Ты знаешь почему?

Спасибо, Ромен

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
2 101
4

Ответы 4

Если вы не добавите [weak self], блок завершения сохранит self, и это не лучший способ использовать блоки. У вас должна быть ссылка (сохранена) на вашего координатора, и ее следует выпустить, когда вы закончите с ней.

Управление памятью в RxSwift

Когда вы избавляетесь от [weak self], блок создает сильную ссылку на self, так что он не освобождается, когда любой другой код выполняется с его использованием. Сделав ссылку слабой, self может быть освобожден, что, вероятно, и происходит. Это означает, что нет другого объекта с сильной ссылкой на self, поэтому он равен нулю и вызов не будет выполнен. Избавление от него может создать цикл сохранения, поэтому вы должны быть осторожны с этим.

Да, ты прав. Однако я не понимаю, почему, но я попытался добавить печать в свое закрытие, чтобы прослушать подписку: с [weak self] _ ничего не происходит, а без него все работает ...

vermotr 18.07.2018 08:58

Похоже, у вас есть другие проблемы с зависимостями.

ymutlu 18.07.2018 09:19

Если он не выполняется, это, вероятно, связано с тем, что ваш координатор освобожден до срабатывания события. Я полагаю, что здесь нет четкой ссылки на вашего предыдущего координатора. Вы можете проверить это, добавив print(...) в deinit.

Ben 14.05.2019 09:45

В Swift 4.2 вы можете спокойно переписать фрагмент как:

self.viewModel.didShowNextView
    .subscribe(onNext: { [weak self] in
        guard let self = self else { return } 
        self.showNextView()
    })
    .disposed(by: disposeBag)

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

Нет разницы между кодом, который вы написали выше, и просто использованием self?.

Luis 08.03.2021 15:38

просто держите ссылку на этого координатора в его родительском координаторе вот так

private var childCoordinators = [CoordinatorType]()

так что он не будет освобожден

Другие вопросы по теме