Фу, это позволяет упаковать много разных проблем в крошечный код :-) Это объяснение длинное, поэтому вы можете узнать, что знаете его первую часть, но можете начать с самого начала ...
NSImage(byReferencingFile)
- это так называемый «неудачный инициализатор», то есть инициализатор, который возвращает NSImage?
- необязательный, который может или не может содержать объект NSImage
.
Причина в том, что создание файла NSImage
может привести к ошибке (предположим, что файл не найден).По этой причине, она возвращает необязательную, что вы должны проверить и разворачивать:
if let img = NSImage(byReferencingFile: somePath) {
// img will be a valid NSImage
}
else {
// img was not valid, handle error here if you want
}
Теперь, если вы попробуете и назначьте NSImage?
(как возвращаемый failable инициализатора) к неопциональным NSImage
, вы будете получить ошибку, потому что вы не можете сделать это - вам нужно сделать развертку, как показано выше, вместо:
// error: value of optional type 'NSImage?' not unwrapped; did you mean to use '!' or '?'?
let img: NSImage = NSImage(byReferencingFile: somePath)
Один из способов справиться с этим, как указано в приведенном выше сообщение об ошибке, вместо того, чтобы разворачивать изображение с if … let
, это «принудительно развернуть», например:
let img: NSImage = NSImage(byReferencingFile: somePath)!
// note exclamation mark -^
Это !
средство: не утруждайте себя проверкой на нуль, просто предположите, что результат действителен и разворачивает его. Это иногда хорошая идея, но обычно это очень плохая идея. Если вы когда-либо принудительно развернете нулевое значение, ваша программа выйдет из строя с ошибкой. Поэтому, если вы не на 100% уверены, что нет возможного способа, чтобы значение могло быть nil (что не очень распространено), вы должны избегать этого.
Хорошо, так как же Any!
влияет на все это?
Тип с !
после того, как он «неявно разворачивается». Это варианты, но вам не нужно вручную принудительно разворачивать. Вы можете просто получить к ним доступ, как обычные значения, но опять же, если вы когда-либо достигнете нулевого значения, ваше приложение перестанет работать.
Таким образом, вы могли бы написать следующее:
let img: NSImage! = NSImage(byReferencingFile: somePath)
// or, this is basically the same thing:
let img = NSImage(byReferencingFile: somePath) as NSImage!
Теперь вы можете использовать img
, как если бы это было не обязательным. Но если бы это было когда-нибудь, то, как и раньше, оно потерпело крах. Разница в том, что он сработает, когда вы используйтеimg
, а не когда вы назначили его img
.
И наконец, Any
- это тип, который может содержать любой тип, но довольно бесполезен, не возвращая реальный тип. Обычно вы должны делать это с помощью as?
. as?
проверяет, содержит ли этот номер Any
и возвращает необязательный параметр, содержащий значение, или nil, если он содержит какой-либо другой тип.
Если вы поместили опцию в Any
и попытаетесь извлечь ее как необязательную, она не сработает и вернет нуль, поскольку тип, который вы вставляете, не совпадает с типом, который вы пытаетесь выбраться ,
Если вы используете as
без вопросительного знака, это приведет к извлечению, не обернув его дополнительным, и, как вы догадались, взорвется во время выполнения, если это когда-либо случилось. На самом деле это настолько опасно, что, глядя невинно, что в новой версии бета-версии Swift 1.2 она была заменена на as!
, чтобы соответствовать ее силовому открытию. В первом примере вы помещаете NSImage?
, вы извлекаете необязательный номер NSImage
и используете as
, поэтому вы получаете утверждение времени исполнения.
В любом случае, Any!
сочетает в себе все перечисленные выше функции в один восхитительный подпружиненный deathtrap. Он весело возьмет необязательный тип, а затем позволит вам извлечь его содержимое как необязательное без проверки.Это то, что происходит в вашем коде - вы помещаете необязательный код в Any!
, а затем извлекаете его как необязательный. Это почти наверняка плохая идея, так как она потерпит крах, если ваш графический файл никогда не будет найден, поэтому вам намного лучше использовать код в самом начале этого ответа, чтобы извлечь значение из изображения.
Спасибо за отличный ответ. Теперь я вижу, что (если я прав) в первом примере я пытался использовать ** Необязательный ** в NSImage. Вернемся к примеру: существует ли простой способ вернуть NSImage из Any без объявления его также как необязательного ('var tmp: Any? = NSImage (byReferencingFile: somePath)'), потому что это, вероятно, моя реальная проблема? – piteer