在Swift中检查nil的非可选值的最佳方法

时间:2017-10-30 15:45:56

标签: objective-c swift null optional nullable

在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

我在这里有几个问题:

  1. 我注意到unsafeBitCast(_:to:)的{​​{3}}说它"打破了Swift类型系统的保障,"但在Swift文档中是否有一个地方可以解释这些保证可以被打破,以及如何/何时?
  2. 检查此案例的最佳,最惯用的方法是什么?编译器不允许我检查是否mailComposeViewController == nil,因为它不是可选的。

3 个答案:

答案 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被记录为机器字大小。)