Swift Memory Management: хранение функций в var
Я ищу лучшую практику для хранения функций как переменных в других объектах. В частности, я стараюсь избегать сохранения циклов, присущих захвату self
в функции.
Исходя из target-c и блоков, я обычно делал бы что-то вроде этого:
__weak id _self = self;
iVar.someBlock = ^{
[_self doSomething];
};
Конечно, iVar
класс скопирует блок и сохранит его. Цикл сохранения не существует, потому что я захватил __weak id _self
,
В Swift я немного менее уверен, тем более что я могу передавать функции / методы класса. Итак, скажем, в iVar
класс у меня есть:
class iVarClass {
var callBack:() -> ()?
func jumpUpAndDown(){
//Weeeeeee!
self.callBack?()
}
}
Теперь в моем "главном" классе у меня есть переменная экземпляра вышеупомянутого класса, и я делаю:
class mainClass {
var iVar: iVarClass
init(iVar:iVarClass){
self.iVar = iVar
iVar.callback = self.doSomething
}
func doSomething(){
self.iVar.jumpUpAndDown?()
}
}
У нас есть цикл сохранения здесь? Я бы так подумал, и я думаю, что, возможно, мне нужно сделать callback
слабый:
weak var callBack:() -> ()?
Конечно, я мог бы сделать что-то подобное в основном классе:
init(iVar:iVarClass){
self.iVar = iVar
weak var _self = self
iVar.callback = {
_self?.doSomething()
}
}
Но так приятно иметь возможность передавать функции класса в качестве аргументов! Кроме того, если мне нужно сделать callback
слабый, тогда я думаю, что потерял бы способность назначать ему закрытие (потому что после назначения закрытие будет освобождено из памяти только с одной слабой ссылкой).
Кроме того, обратите внимание, что ответственность за управление памятью теперь лежит на получателе, а не на назначителе, но, поскольку получатель не может знать источник назначения, он не может быть действительно ответственным. Другими словами, теперь должен быть неявный договор между получателем и цессионарием о том, какую функцию следует передавать, что является хрупким и не рекомендуется. Когда ответственный исполнитель отвечает, он может предпринять шаги, чтобы гарантировать отсутствие цикла сохранения, но получатель не может предпринять такие шаги.
Это заставляет меня думать, что мы никогда не должны передавать функцию класса другому объекту. Это слишком опасно. Вы не можете знать, как получатель будет хранить / использовать его.
Или я что-то упустил? Свифт волшебным образом решает эту проблему за кулисами?
Обновить
@Kirsteins указал на то, о чем я забыл: захватить списки. Таким образом, вместо того, чтобы явно объявить weak var _self = self
, Вы можете объявить это в закрытии вместо:
init(iVar:iVarClass){
self.iVar = iVar
iVar.callback = { [weak self] in
self?.doSomething()
}
}
Это лучше, но не так элегантно, как простое назначение функции класса.
Я думаю, что я хочу, чтобы Swift автоматически преобразовал функцию класса в замыкание со списком захвата, поэтому мне не нужно это делать. Если честно, это не совсем сложно, но, безусловно, намного красивее, если бы я мог просто назначить функцию класса. Черт, даже это было бы лучше
self.iVar.callback = weak self.doSomething
1 ответ
Не могли бы вы сделать что-то вроде этого:
class mainClass {
var iVar: iVarClass
init(iVar:iVarClass){
self.iVar = iVar
func go() {
self.doSomething()
}
iVar.callback = go
}
func doSomething(){
self.iVar.jumpUpAndDown?()
}
}
Насколько я понимаю, таким образом вы не будете захватывать self
непосредственно и, таким образом, позволит избежать цикла сохранения.