Ответ 1
Это НЕ ошибка. Это просто ваш тип закрытия, который является неправильным.
Правильный тип должен возвращать необязательный Void
, чтобы отразить дополнительную цепочку:
let clos = { ()->()? in currentBottle?.jiggle() }
Проблема в деталях:
- Вы объявляете свое закрытие замыканием, которое возвращает
Void
(а именно->()
). - Но помните, что, как и каждый раз, когда вы используете необязательную цепочку, возвращаемый тип всего выражения необязательного типа. Поскольку ваше закрытие может возвращать
Void
, еслиcurrentBottle
существует... илиnil
, если это не так!
Итак, правильный синтаксис состоит в том, чтобы сделать ваше закрытие возвратом Void?
(или ()?
) вместо простого Void
class BottleLayer {
func jiggle() { println("Jiggle Jiggle") }
}
var currentBottle: BottleLayer?
currentBottle?.jiggle() // OK
let clos = { Void->Void? in currentBottle?.jiggle() } // Also OK
let clos = { () -> ()? in currentBottle?.jiggle() } // Still OK (Void and () are synonyms)
Примечание. Если вы позволили Swift вывести правильный тип для вас вместо того, чтобы явно его принудительно использовать, это устранило бы проблему для вас:
// Even better: type automatically inferred as ()->()? — also known as Void->Void?
let clos = { currentBottle?.jiggle() }
[EDIT]
Дополнительный трюк: непосредственно назначить необязательную цепочку переменной
Вы можете даже назначить функцию непосредственно переменной, например:
let clos2 = currentBottle?.jiggle // no parenthesis, we don't want to call the function, just refer to it
Обратите внимание, что тип clos2
(который явно не указан здесь и поэтому автоматически вызывается Swift) в этом случае не Void->Void?
- а именно функция, которая возвращает либо nil
или Void
), как в предыдущем случае, но - (Void->Void)?
, что является типом для необязательной функции типа Void->Void
".
Это означает, что clos2
сам "либо nil
, либо функция возвращает Void
". Чтобы использовать его, вы можете снова использовать необязательную цепочку, просто так:
clos2?()
Это будет оцениваться как nil
и ничего не делать, если clos2
сам nil
(вероятно, потому что currentBottle
сам по себе nil)... и выполняет закрытие - таким образом, код currentBottle!.jiggle()
- и возвращает Void
если clos2
не-ниль (вероятно, потому что сам currentBottle
не равен нулю).
Тип возврата clos2?()
сам действительно Void?
, так как он возвращает ниль или Void.
Выполнение разницы между Void
и Void?
может показаться бессмысленным (в конце концов, функция jiggle
ничего не возвращает в любом случае), но она позволяет вам делать такие мощные вещи, как тестирование Void?
в if
, чтобы проверить, действительно ли был вызван вызов (и возвращен Void
а именно ничего) или не произошло (и возвращает nil
):
if clos2?() { println("The jiggle function got called after all!") }
[EDIT2] Как вы (@matt) указали на себя, этот другой вариант имеет еще одно важное отличие: он оценивает currentBottle?.jiggle
в то время, когда это выражение повлияло на clos2
. Поэтому, если currentBottle
nil
в это время, clos2
будет nil
... даже если currentBottle
получил значение, отличное от нуля.
И наоборот, clos
затрагивается самой закрытием, а необязательная цепочка оценивается только каждый раз, когда вызывается clos
, поэтому она будет оценивать до nil
, если currentBottle
равна nil... но будет оцениваться как non-nil и вызывается jiggle()
, если мы назовем clos()
в более позднее время, когда точка currentBottle
стала не нулевой.