Назначение self в качестве реализации делегата приведет к утечке памяти?

#swift

#swift

Вопрос:

Привет, у меня есть 2 протокола, второй из которых имеет и ссылку на первый тип протокола, а также возвращает self для этой ссылки. вот код.

 protocol MainViewModelInput {
    func loginButtonAction()
    func registerButtonAction()
}

protocol MainViewModelProvider {
    var input: MainViewModelInput { get }
}

extension MainViewModelProvider where Self: MainViewModelInput {
    var input: MainViewModelInput { return self }
}
 

итак, когда я реализую это так, создает ли это утечку памяти?

 class MainViewModel: MainViewModelProvider, MainViewModelInput {

    private let router: AnyRouter<MainRoute>

    init(router: AnyRouter<MainRoute>) {
        self.router = router
    }
}

extension MainViewModel {

    func loginButtonAction() {
        router.trigger(.login)
    }

    func registerButtonAction() {
        router.trigger(.register)
    }
}
 

Моя идея заключается в том, что, если MainViewController создается объект типа MainViewModel , а input также содержится ссылка на этот объект, он никогда не будет выпущен, я не прав?

Спасибо.

Комментарии:

1. Создайте input a weak var , который потребует, чтобы ваш протокол был протоколом класса

2. Спасибо, я просто хотел знать, нужно ли это? потому что, возможно, в других случаях кто-то захочет использовать его для структур, разве это не возможно?

3. Хорошо, я не смотрел достаточно близко. Поскольку input это вычисляемое свойство, оно не создает ссылку, так что, я думаю, у вас все хорошо.

4. хм, поскольку он возвращает только self, а не назначает delegate как self, это не приведет к утечке, я правильно понял?

5. В вашем расширении протокола вы определили input как вычисляемое свойство только для получения, так что да, все будет в порядке.

Ответ №1:

Обычно вы хотите, чтобы ваш делегат был a weak var , чтобы избежать циклов сохранения в случаях, подобных вашему — именно так шаблон делегирования реализуется, например, UIKit в таких классах, как UITableView

Однако в вашем случае вы определяете input переменную как вычисляемое свойство, доступное только для получения. Вычисляемые свойства в Swift работают во многом как функция — они ничего не хранят, они просто предоставляют средства для косвенного извлечения некоторых значений.

Это может сработать, но вам нужно быть особенно осторожным. Пример: давайте изменим ваш код, например, так:

 class MainViewModel: MainViewModelProvider, MainViewModelInput {

    private let router: AnyRouter<MainRoute>

    var input: MainViewModelInput?

    init(router: AnyRouter<MainRoute>) {
        self.router = router

        input = self
    }
}
 

Что мы сделали: мы переопределили реализацию input property по умолчанию — это больше не вычисляемое свойство. И мы также ввели утечку памяти — теперь self содержит сильную ссылку на себя.

Итак, в целом: ваша идея может сработать, но только если вы будете очень осторожны, чтобы никогда не переопределять input свойство для хранения и ссылки self .

Ответ №2:

Что я хотел бы сделать, так это создать функцию, которая проверяет, так ли self MainViewModelInput это.

 if let modelInput = self as? MainViewModelInput {
    // Here you should have access to protocol implementation
}