Я был захвачен закрытием до инициализации всех членов - но я их инициализировал - PullRequest
2 голосов
/ 16 февраля 2020

Это игрушечный пример, но он точно уменьшает ситуацию, в которой я нахожусь:

class MyDataSource: UITableViewDiffableDataSource<String,String> {
    var string : String?
    init(string:String?) {
        self.string = string
        super.init(tableView: UITableView()) { (_, _, _) -> UITableViewCell? in
            print(self.string) // error
            return nil
        }
    }
}

Я пытаюсь сделать свой источник данных табличного представления автономным, и мой способ сделать это ( до сих пор) является подклассом UITableViewDiffableDataSource. Это работает хорошо, за исключением случаев, когда я пытаюсь дать своему подклассу собственный инициализатор. В игрушечном примере показана проблема.

Способ, которым я хочу заполнить ячейку, полностью зависит от значения, которое может измениться позднее в жизни источника данных. Следовательно, он не может быть жестко закодирован в функцию провайдера сотовой связи. Я не могу сослаться здесь просто на string, значение, которое было передано в инициализаторе; Я должен сослаться на self.string, потому что другой код сможет впоследствии изменить свойство экземпляра string этого источника данных, и я хочу, чтобы провайдер ячейки использовал это новое значение, когда это произойдет.

Тем не менее, я получаю сообщение об ошибке «Я был захвачен закрытием до инициализации всех членов». Это кажется несправедливым. Я сделал инициализацию моего string свойства экземпляра перед вызовом super.init. Таким образом, он имеет значение в самый ранний момент, когда метод провайдера ячейки может быть вызван.

Ответы [ 2 ]

3 голосов
/ 16 февраля 2020

Хотя я не совсем уверен , почему Swift не позволяет этого (что-то связанное с захватом self, чтобы создать замыкание до фактического вызова super.init), я делаю по крайней мере, знаю обходной путь для этого. Вместо этого перехватите слабую локальную переменную и после вызова super.init установите для этой локальной переменной значение self:

class MyDataSource: UITableViewDiffableDataSource<String,String> {
    var string : String?
    init(string:String?) {
        self.string = string
        weak var selfWorkaround: MyDataSource?
        super.init(tableView: UITableView()) { (_, _, _) -> UITableViewCell? in
            print(selfWorkaround?.string)
            return nil
        }

        selfWorkaround = self
    }
}

Однако единственная проблема в этом заключается в том, что если выполняется замыкание во время вызов super.init, тогда selfWorkaround будет равен нулю внутри замыкания, и вы можете получить неожиданные результаты. (В этом случае, однако, я не думаю, что это так - поэтому вы должны быть в безопасности, чтобы сделать это.)

Редактировать: причина, по которой мы делаем локальную переменную weak, состоит в том, чтобы предотвратить self объект от утечки.

3 голосов
/ 16 февраля 2020

вы можете получить доступ к себе через tableView.datasource, и это решит большую часть проблемы.

...