为什么Objective-C API会隐式返回未包装的选项?

Nic*_*ckH 14 interop objective-c optional ios swift

我对此感到困惑.如果我们把方法cellForRowAtIndexPath:UITableView,例如,它的方法签名是:

func cellForRowAtIndexPath(_ indexPath: NSIndexPath!) -> UITableViewCell!
Run Code Online (Sandbox Code Playgroud)

它的返回值是:

表示表格单元格的对象,如果单元格不可见或者indexPath超出范围,则为nil.

这听起来是使用标准可选项的完美理由.事实上,由于Objective-C中的所有基于指针的类型都可以为nil ......似乎有意义的是所有Objective-C指针类型都应该作为标准选项导入.

我从WWDC的讲话中知道,他们说这是隐含的未解决的选项:

  • 可以明确测试为零
  • 可以直接访问基础值的属性/方法
  • 可以隐式转换为其基础值

从Apple的使用Swift与Cocoa和Objective-C:

当您以这种可选类型访问该值而不首先安全地解包它时,隐式解包的可选项检查该值是否缺失.如果缺少该值,则会发生运行时错误.

所以,不是将可能的nil值作为可选项导入到Swift中,而是决定将其导入为一种状态,表明它永远不会是零...但可能是?听起来他们通过这样做完全否定了Swift for Objective-C API中可选类型的安全性.我似乎缺少什么?

而不是给出编译时错误或警告,他们认为运行时错误更好?这非常令人困惑.

考虑到似乎没有什么能回答我所看到的这个问题......我认为对于其他所有人来说,我只是没有看到,但是......为什么会这样?

if let当他们在Swift中使用Objective-C API时,是否真的只是为了节省人们使用或可选链接,还是更多?

das*_*ght 5

当你在Swift中创建一个隐式解包的可选项时,并不意味着它总是非零:所有这意味着你告诉编译器当你访问它们的属性时,你希望对象是非属性的nil.可以显式检查您引用的对象nil; 将其设置为nil不会导致异常,除非您在此之后尝试访问其任何属性.

当Apple使用隐式解包的选项时参数

func tableView(_ tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
Run Code Online (Sandbox Code Playgroud)

功能,他们让你节省一些额外的if- let.在这种情况下,他们知道他们从未通过你nil; 在其他情况下,他们不知道它,他们希望你 - nil检查对象.

它们也允许你返回nil.他们应该检查结果nil,当然,除非您决定自己调用该功能.虽然我无法想出cellForRowAtIndexPath从您自己的代码中调用的正当理由,但如果您确实拨打了电话,那么您有责任检查其返回值nil.

如果您考虑做参数的替代UITableView?NSIndexPath?替代,所有的实现必须经过要么使用感叹号tableViewindexPath,或使用if- let成语.与此选择相比,隐式展开的类型看起来是更好的选择.

  • "他们有效地向你保证,他们传递给你的tableView和indexPath都不会是nil"Nope.没有这样的"承诺".*自动导入Swift*的Objective-C API中的所有*对象指针类型*成为隐式解包的选项; 没有涉及情报.在某些情况下,许多这些API可以(实际上应该)返回"nil". (3认同)
  • @NickH:这是绝对安全和便利之间的权衡.因为它可能是'nil`它必须是可选的.在您确定它不是"nil"(并且如果您错了,它会抛出错误)的情况下,隐式解包会使您更方便,就像您在任何地方明确地展开它一样.如果您不确定它不是'nil`,您仍然可以使用可选绑定和可选链接.所以基本上你是程序员可以选择合适的方式来使用它.这样Apple就不必在整个API中明确注释可空/不可空. (2认同)

Jen*_*ong 5

以下是Greg Parker在lists.swift.org 的swift-users中的回答:

作为隐式解包可选导入是一种可用性 妥协。大多数 Objective-C 指针实际上从来都不是 nil。如果指针为零,并且作者没有检查,那么进程就会故意停止。这并不比编写 Objective-C 代码时的行为更糟​​糕。IUO 导入只是权宜之计。从长远来看,每个 Objective-C 接口都应该明确注释,以便 Swift 可以更精确地导入它们。在您自己的代码中,您可以在头文件中使用 NS_ASSUME_NONNULL_BEGIN/END 。这些标记内的每个未注释的对象指针都是非空的。