我正在尝试使用guard语句来检查nil。
我很困惑为什么下面的让它通过并生成BAD_EXEC错误:
guard let event:Event! = eventsImagesLoading.removeValueForKey(location) else {
return
}
images[location] = responseData
event!.iconImgData = images[location]
我试图在方法调用后检查"event"是否为零。如果是的话,它应该返回。但事实上,它在活动中滑了过去并崩溃了!。iconImageData。。。线
其他答案向您展示了如何解决问题,但并没有真正解释为什么会出现这种错误,所以我想我会参与其中。
guard let ... else
语句与if let ...
非常相似,它试图将一个可选的(通常只要不是nil
)的未包装值绑定到同一底层类型的非可选不可变值;使用可选绑定
var a: Int? = 5
if let b = a {
// b unwrapped, type inferred to non-optional type Int
print(b) // "5"
}
如果a
的值为nil
,则上述绑定将失败,因为默认情况下(通过类型推断),b
的类型为Int
,不能容纳nil
。
在这种情况下,显式声明b
为隐式展开的可选项是没有意义的,因为即使a
为零,这也将允许成功绑定。等效的非感测块将显式声明b
为可选,此后可选a
(Int?
)到可选b
(Int?
)的"尝试的可选绑定"自然总是成功的,并且if let ...
块减少为完全冗余的块本地分配。
a = nil
if let b: Int! = a {
print(b) // "nil"
// wups, we managed to bind a to b even though a is nil ...
// note also this peculiarity
print(b.dynamicType) // Optional<Int>
let c: Int! = nil
print(c.dynamicType) // ImplicitlyUnwrappedOptional<Int>
}
if let b: Int? = a {
print(b) // nil
// wups, we managed to bind a to b even though a is nil ...
}
请注意,无论我们显式指定b
为类型Int?
(可选)还是类型Int!
(隐式展开可选),传递到if let
块的绑定的不可变b
在这两种情况下都只是常规可选(类型Int?
)。这就解释了为什么需要在guard let
子句之后展开event
(event!.iconImgData
),尽管我们声明它是隐式展开的类型。
因此,在您的示例中,guard let ... else
语句将不会捕获eventsImagesLoading.removeValueForKey(location)
是nil
的情况,因为绑定到event
(它是隐式展开的可选类型Event!
)将成功,即使对于nil
的情况也是如此。
func foo() {
let bar : Int? = nil
guard let _: Int! = bar else {
print("this is surely nil")
return
}
print("but an implicitly unwrapped optional will fall through")
}
foo() // "but an implicitly unwrapped optional will fall through"
对于需要延迟初始化的免疫表,通常只应使用隐式展开选项(值nil
,直到初始化)。在隐式展开的可选项初始化后,其值不应为nil
(而在上面的示例中,通过可选绑定初始化后,它的值仅为nil
)。
此外,您通常应该让编译器推断出您试图在guard let INFER_THIS = ... else
或if let INFER_THIS = ...
子句中绑定到的不可变的非可选类型。
我们可以考虑是否应该允许它使用可选绑定到可选类型(保证成功),但这是另一个讨论。
将Event!
更改为Event
(第1行),将event!
更改为event
(第5行)。
guard let event:Event = eventsImagesLoading.removeValueForKey(location) else {
return
}
images[location] = responseData
event.iconImgData = images[location]