Путаница по поводу слабого делегата в Swift

Допустим, у нас есть протокол

protocol MyProtocol {
    fun someFunc()
}

class AClass {
    var delegate: MyProtocol?
}

AClass не заботится о том, является ли делегат классом или структурой. Что я хочу, так это то, что иногда делегат может быть классом, а иногда он может быть назначен структуре.

Мой вопрос в том, должен ли я сделать делегата «слабым».

Если это так, я должен сделать MyProtocol «протоколом класса», чтобы делегат был только классом. Если нет, когда я назначаю делегата классу, как я могу избежать сохранения цикла?

Спасибо за любую подсказку!


person echo    schedule 27.10.2017    source источник


Ответы (2)


должен сделать делегата «слабым»

Ответ заключается в том, что если MyProtocol не ограничен классами, вы не можете сделать его слабым, компилятор вам не позволит.

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

как я могу избежать сохранения цикла?

Это означает, что вы должны быть осторожны, чтобы ваш делегат не содержал сильных ссылок на экземпляр класса. Так, например

struct ConcreteDelegate: MyProtocol
{
    fun someFunc() {}
    var instance: AClass

    init()
    {
        instance = AClass()
        instance.delegate = self
    }
}

Вызывает опорный цикл. Его можно сломать, объявив instance как

    weak var instance: AClass! 

В качестве альтернативы и лучшего решения (IMO) ваши функции протокола могут передавать экземпляр в качестве параметра, поэтому делегату никогда не нужно хранить ссылку на экземпляр.

protocol MyProtocol {
    func someFunc(caller: AClass)
}

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

person JeremyP    schedule 27.10.2017
comment
Спасибо за Ваш ответ! - person echo; 27.10.2017

Я думаю, вы забыли, что struct не ссылочный тип, а тип значения. Это означает, что у класса есть ссылка в куче памяти, а у структур и перечислений нет. Учитывая этот факт, нет смысла ставить weak, если делегатом вашего протокола является struct, потому что это не может вызвать цикл удержания.

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

Если вы хотите проверить это, поставьте deinit функций при тестировании и посмотрите, правильно ли ваш класс деинитирован и не хранится в памяти. Это в основном то, что я знаю, надеюсь, это поможет вам.

person Arrabidas92    schedule 27.10.2017