Я обнаружил это странное поведение:
Рассмотрим следующий код:
func foo(_ x: () -> Void) {
}
class Bar {
func bar() {
print("hello")
}
}
var bar: Bar? = Bar()
Эти компиляции:
foo(bar?.bar ?? {})
но это не так:
DispatchQueue.main.async(execute: bar?.bar ?? {})
выдает ошибку:
Невозможно преобразовать значение типа '() -> ()' в ожидаемый тип аргумента '@convention (block) () -> Void'
Теперь, если я изменю bar
на:
func bar() -> (() -> Void)? {
return { print("hello") }
}
и затем сделайте:
DispatchQueue.main.async(execute: bar() ?? {})
Он компилируется!
Так что это определенно не из-за оператора ??
Вопрос: Можете ли вы объяснить это поведение?
Все, что ниже этого пункта, - мои эксперименты.
Я заметил, что единственная разница между методом async
и foo
заключается в том, что параметр execute
помечен @convention(block)
.
Гипотеза: Я не могу передать необязательные выражения цепочки в параметры, отмеченные @convention(block)
.
Но, похоже, это неправильно, так как я могу это сделать, но он по-прежнему не компилируется:
DispatchQueue.main.async(execute: Bar().bar ?? {})
Также кажется, что я могу привести выражение к () -> Void
, и оно волшебным образом компилируется:
DispatchQueue.main.async(execute: (bar?.bar ?? {}) as () -> Void)
Не является ли bar?.bar ?? {}
уже типа () -> Void
? Это не имеет смысла!
Другой способ сделать его компилируемым - извлечь bar?.bar
как локальную переменную:
let barFunc = bar?.bar
DispatchQueue.main.async(execute: barFunc ?? {})
что имеет еще меньше смысла ...