我想弄明白为什么
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会做这份工作吗?有什么不同吗?
发布于 2015-03-07 20:17:37
这能将许多不同的问题打包成一小部分代码:-)这个解释很长,所以你可能会发现你知道它的第一部分,但最好从一开始就开始.
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? (如可故障初始化器返回的)分配给一个非可选的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%确定该值不可能为零(这不是很常见),否则您应该避免这样做。
那么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是否包含该类型,并返回包含该值的可选选项,如果包含其他类型,则返回零。
如果您将一个可选项放入一个Any中,然后尝试将其解压为非可选类型,则它将失败并返回零,因为您输入的类型与尝试退出的类型不相同。
如果您使用没有问号的as,这会强制提取而不将其包装在可选的范围内,并且,您猜到了,如果错误的话,它将在运行时崩溃。事实上,这看起来很危险,在新的1.2测试版的Swift中,它已经被as!所取代,以匹配它的强制展开特性。在第一个示例中,您输入了一个NSImage?,您提取了一个非可选的NSImage,并使用了as,因此您得到了一个运行时断言。
总之,Any!将上述所有功能结合到一个令人愉快的春季死亡陷阱中.它将愉快地采取一种可选类型,然后允许您将其内容提取为非可选类型,而无需检查。这就是在您的代码中发生的事情--您正在将一个可选的内容放入一个Any!中,然后将其作为一个非可选的。这几乎肯定是个坏主意,因为如果找不到您的图像文件,它就会崩溃,所以您最好在这个答案一开始就使用代码从图像中提取值。
发布于 2015-03-07 19:54:49
因为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.
}这有用吗?
https://stackoverflow.com/questions/28918937
复制相似问题