在Swift中,它很少见,但可能最终得到一个具有零值的非可选类型的值。正如this question的答案中所解释的那样,这可能是由于与Swift结合的不良Objective-C代码引起的:
- (NSObject * _Nonnull)someObject {
return nil;
}
或者糟糕的Swift代码:
class C {}
let x: C? = nil
let y: C = unsafeBitCast(x, to: C.self)
在实践中,我使用MFMailComposeViewController
中的MessageUI
API遇到了这个问题。以下内容创建了一个非可选MFMailComposeViewController
,但如果用户尚未在Mail中设置电子邮件帐户,则以下代码会与EXC_BAD_ACCESS
崩溃:
let mailComposeViewController = MFMailComposeViewController()
print("\(mailComposeViewController)")
调试器显示mailComposeViewController
的值,如下所示:
mailComposeViewController = (MFMailComposeViewController) 0x0000000000000000
我在这里有几个问题:
unsafeBitCast(_:to:)
的{{3}}说它"打破了Swift类型系统的保障,"但在Swift文档中是否有一个地方可以解释这些保证可以被打破,以及如何/何时?mailComposeViewController == nil
,因为它不是可选的。答案 0 :(得分:5)
即使Apple的API有时也会返回nil
,因为未在API中标记为可选的类型。解决方案是分配给Optional。
例如,有一段时间traitCollectionDidChange
返回了一个UITraitCollection,即使它实际上可能是nil
。您无法检查nil
,因为Swift不会让您检查nil
的非可选项。
解决方法是立即将返回值分配给UITraitCollection?
并检查 <{em>} nil
。这种事情应该适用于你的用例(尽管你的邮件示例不是用例,因为你从一开始就做错了。)
答案 1 :(得分:0)
我有同样的问题,但我使用Apple文档中的建议。
来自文档:
在呈现邮件撰写视图控制器之前,请始终调用 canSendMail()方法查看当前设备是否配置为 发送电子邮件。如果用户的设备未设置为传送 电子邮件,您可以通知用户或只是禁用电子邮件发送 应用程序中的功能。你不应该试图使用它 接口,如果canSendMail()方法返回false。
if !MFMailComposeViewController.canSendMail() {
print("Mail services are not available")
return
}
考虑使用unsafeBitCast(_:to:)
。
主要的问题是,在这个方法中,如果指针可以符合我们期望的类型,我们在没有任何验证的情况下转换指向Swift值的指针,从我的观点来看,它是非常危险的,因为它会产生崩溃
答案 2 :(得分:0)
使用实际的Swift指针类型可能有更好的方法,但一个选项可能只是查看地址:
func isNull(_ obj: AnyObject) -> Bool {
let address = unsafeBitCast(obj, to: Int.self)
return address == 0x0
}
(Int
被记录为机器字大小。)