2015-03-07 2 views
0

Я пытаюсь понять, почемуNSImage на приведение Любое обратное приведение его обратно NSImage

var tmp: Any = NSImage(byReferencingFile: somePath) 
var img: NSImage = tmp as NSImage 

не будет работать и вызовет ошибку, но

var tmp: Any = NSImage(byReferencingFile: somePath) as Any! 
var img: NSImage = tmp as NSImage 

будет делать эту работу? Как все иначе?

ответ

1

Фу, это позволяет упаковать много разных проблем в крошечный код :-) Это объяснение длинное, поэтому вы можете узнать, что знаете его первую часть, но можете начать с самого начала ...

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!, а затем извлекаете его как необязательный. Это почти наверняка плохая идея, так как она потерпит крах, если ваш графический файл никогда не будет найден, поэтому вам намного лучше использовать код в самом начале этого ответа, чтобы извлечь значение из изображения.

+0

Спасибо за отличный ответ. Теперь я вижу, что (если я прав) в первом примере я пытался использовать ** Необязательный ** в NSImage. Вернемся к примеру: существует ли простой способ вернуть NSImage из Any без объявления его также как необязательного ('var tmp: Any? = NSImage (byReferencingFile: somePath)'), потому что это, вероятно, моя реальная проблема? – piteer

0

Поскольку NSImage(byReferencingFile: somePath) возвращает Дополнительно. Если вы посмотрите на документации вы можете увидеть, что подпись:

init?(byReferencingFile filename: String)

Знак вопроса после init означает, что инициализатор может потерпеть неудачу, и что он возвращает факультативного значения. Поэтому, когда, например, файл не существует, он возвращает nil вместо экземпляра NSImage.

Вы можете fix это, делая это ...

var tmp: Any = NSImage(byReferencingFile: somePath) 
var img: NSImage? = tmp as? NSImage 

... Это на самом деле не исправить, хотя.

Ваш второй пример работает, потому что вы принудительно разворачиваете опцию, используя Any!. Вы в основном говорите, игнорируете значение опциона, просто дайте мне изображение, которое оно обертывает. Но это приведет к сбою, если изображение не может быть загружено.

В идеале, что вы хотите сделать это:

if let image = NSImage(byReferencingFile: somePath) { 
    // Here the "if let" has checked and unwrapped the optional 
    // and you can be sure that image is not nil. 
} 

ли это помощь?

+0

Спасибо за анзер, да это помогает! Из-за Любых я полностью упустил тот факт, что Any не был NSImage, но необязательным. Предлагаемое «исправление» (да, я знаю, что я не должен делать это таким образом, но это только теоретический вопрос) с «var img: NSImage? = tmp as? NSImage' я думаю, что он всегда будет присваивать значение nil переменной ** img **, даже если ** tmp ** var содержит действительный NSImage – piteer

Смежные вопросы