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 непосредственно и, таким образом, позволит избежать цикла сохранения.

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