сам захвачен закрытием до того, как все члены были инициализированы, но я их инициализировал
Это игрушечный пример, но он точно уменьшает мою ситуацию:
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
instance свойство позже, и я хочу, чтобы провайдер ячейки использовал это новое значение, когда это произойдет.
Тем не менее, я получаю сообщение об ошибке "сам захвачен закрытием до инициализации всех членов". Это кажется несправедливым. Я сделал инициализировать мойstring
свойство экземпляра перед вызовом super.init
. Таким образом, он имеет значение в самый ранний момент, когда может быть вызван метод поставщика ячейки.
3 ответа
Хотя я не совсем уверен, почему 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
объект от утечки.
Вы можете получить доступ к себе через tableView.datasource, и он решит большую часть проблемы.
Расширяя ответ Абхираджа Кумара от 16 февраля 2020 года, вот пример использования TableView, предоставленного для "обратной связи", чтобы получить источник данных, который вы прикрепили к таблице... то есть "себя":
class MyDataSource: UITableViewDiffableDataSource<String,String> {
var string : String?
init(string:String?) {
self.string = string
super.init(tableView: UITableView()) { (tableView, _, _) -> UITableViewCell? in
// Very sketchy reach-through to get "self", forced by API design where
// super.init() requires closure as a parameter
let hack_self = tableView.dataSource! as! MyDataSource
let selfDotStr = hack_self.string
print("In closure, self.string is \(selfDotStr)")
return nil // would return a real cell here in real application
}
}
}