Ответ 1
ОБЪЯСНЕНИЕ
ImplicitlyUnwrappedOptional
не является отдельным типом, а обычный Optional
с атрибутом, объявляющим его значение, может быть неявно принудительным (на основе SE-0054):
Однако появление! в конце свойства или типа объявления переменной больше не указывает, что декларация имеет тип IUO; скорее, это указывает, что (1) объявление имеет необязательный тип, и (2) объявление имеет атрибут, указывающий, что его значение может быть принудительно принудительно. (Ни один человек никогда не напишет или не увидит этот атрибут, но мы будем называть его как @_autounwrapped.) Такое объявление в дальнейшем упоминается как декларация IUO.
Таким образом, когда вы используете это:
let array = [button1, button2]
Компилятор выводит тип array
на [UIButton?]
, потому что тип button1
и button2
равен Optional<UIButton>
, а не ImplicitlyUnwrappedOptional<UIButton>
(даже если только один из них был необязательным, он будет выводиться необязательный тип).
Подробнее в SE-0054.
Боковое примечание:
Это поведение не связано с arrays
, в следующем примере тип button2
будет выведен на UIButton?
, хотя существует !
, и в button
есть значение:
var button: UIButton! = UIButton()
func foo() {
let button2 = button // button2 will be of optional type: UIButton?
}
Решение
Если вы хотите получить массив развернутого типа, у вас есть два варианта:
Первый, как Гай Когус, предложенный в его ответе, использует явный тип вместо того, чтобы позволить быстро получить его:
let array: [UIButton] = [button1, button2]
Однако, если на случай, если одна из кнопок содержит nil
, это приведет к сбою Unexpectedly found nil
.
В то время как используя неявно развернутый необязательный вместо необязательного (!
вместо ?
), вы утверждаете, что никогда не будет никого в этих кнопках, я бы предпочел более безопасный вариант второй предложенный EmilioPelaez в своем комментарии. То есть использовать flatMap
, который отфильтрует nil
s, если они есть, и вернет массив развернутого типа:
let array = [button1, button2].flatMap { $0 }