【问题标题】:How is a return value of AnyObject! different from AnyObjectAnyObject的返回值如何!不同于任何对象
【发布时间】:2014-06-05 13:05:11
【问题描述】:

Swift下Cocoa框架中的NSMetadataItem类包含如下函数:

func valueForAttribute(key: String!) -> AnyObject!

我仍在学习强制展开和可选链接之间的区别(和细节)。在上面的函数中,这是否意味着:

  1. key 参数必须有值,并且

  2. 返回值保证有值?

我主要关心的是 返回值后面的感叹号 - 一旦我分配了返回值:

var isDownloadedVal = item.valueForAttribute(NSMetadataUbiquitousItemIsDownloadedKey)

检查时是否需要包含if let 块,或者我是否保证它具有我可以安全检查的值?

【问题讨论】:

    标签: swift forced-unwrapping


    【解决方案1】:

    TLDR:将Foo! 视为Foo

    许多 Cocoa 调用都包含隐式展开的可选项,他们对它的需求很可能是该功能存在的原因。以下是我建议的思考方式。

    首先,让我们考虑一个不涉及AnyObject 的简单案例。我认为UIDevice 就是一个很好的例子。

    class func currentDevice() -> UIDevice!
    

    这里发生了什么?好吧,总是有一个currentDevice。如果返回nil,则表明系统中存在某种深度错误。因此,如果我们在 Swift 中构建此接口,则很可能只返回 UIDevice 并完成它。但是我们需要连接到 Objective-C,它返回 UIDevice*。现在它不应该是nil,但它在语法上可能nil。现在在 ObjC 中,我们通常会忽略这一事实,并且不要在此处进行nil-check(特别是因为nil-messaging 通常是安全的)。

    那么我们如何在 Swift 中表达这种情况呢?好吧,从技术上讲,它是一个Optional<UIDevice>,你最终会得到:

    class func currentDevice() -> UIDevice?
    

    并且您需要在每次使用它时显式地打开它(最好使用if let 块)。那会很快让你发疯,而且毫无意义。 currentDevice() 总是返回一个值。 Optional 是桥接到 ObjC 的工件。

    所以他们发明了一种破解方法来解决这个问题(我认为这确实是一种破解;如果没有 ObjC 的话,我无法想象构建这个功能)。那个 hack 说,是的,它是一个 Optional,但你可以假装它不是,我们保证它永远是一个值。

    那是!。对于这种东西,你基本上忽略了!,假装它把UIDevice还给你,然后继续前进。如果他们对你撒谎并返回nil,那么,那将会崩溃。他们不应该对你撒谎。

    这暗示了一个规则:除非你真的需要,否则不要使用!(而且你几乎只需要在桥接到 ObjC 时使用)。

    在您的具体示例中,这适用于两个方向:

    func valueForAttribute(key: String!) -> AnyObject!
    

    从技术上讲,它需要一个Optional<String>,但这只是因为它桥接到了NSString*。您必须在此处传递非nil。从技术上讲,它会返回您Optional<AnyObject>,但这只是因为它已桥接到id。它承诺不会是nil

    【讨论】:

    • 很好的解释。考虑到 ObjC 的桥接使整个 Optional 概念更有意义。
    • 谢谢,这是一个很好的解释。 “如果他们对你撒谎并返回 nil,那么那将会崩溃。他们不应该对你撒谎。” 尝试返回一个 nil 值会发生什么。
    • 【 class func JSONObjectWithData(data: NSData!, options opt: NSJSONReadingOptions, error: NSErrorPointer) -> AnyObject! 】 我对这个 NSJSONSerialization 类函数有点困惑。当使用无效的 json 时,它仍然会返回一个 nil,那么为什么不使用呢?但是!
    • ObjC->Swift API 转换几乎肯定是由自动化工具(或自动化人,也称为“实习生”)完成的。我强烈怀疑他们是否仔细考虑了每个方法调用的语义。在这种情况下,AnyObject? 会更有意义,您应该打开一个雷达 (bugreport.apple.com) 来请求它。可能任何采用 NSErrorPointer 的方法都应该返回 ?.
    • 我也对此感到困惑,所以感谢您的精彩解释。我特别困惑为什么 tableView:cellForRowAtIndexPath: 中的表格视图参数被键入为“UITableView?” ——我注意到如果你使用代码完成,你会得到“UITableView!”,但是如果你看一下你用 UITableViewController 得到的样板代码,它会给你 UITableView?。由于表格视图调用此数据源方法,tableView 参数永远不能为零,因此不清楚(在您回答之前)为什么需要任何类型的可选。
    【解决方案2】:

    根据 Swift-eBook,其中陈述如下

    „尝试使用!访问不存在的可选值会触发运行时错误。在使用之前,请务必确保可选项包含非零值!强制解包它的值。“

    我会用回答你的前两个问题。

    检查时是否需要包含 if let 块...

    ,这没有必要。

    【讨论】:

    • 谢谢 - 我想我理解 ?! 在定义/访问变量时的使用,但我有点不确定它们在方法签名中的使用。这是否意味着如果valueForAttribute 函数试图返回一个 nil 值,就会发生运行时错误?
    • 这意味着 valueForAttribute 甚至不能返回 nil,因为它必须返回的类型以 ! 结尾。所以 nil 永远不能分配给函数返回的值。而且我不认为 Apple 的库是为了触发运行时错误而构建的。
    猜你喜欢
    • 1970-01-01
    • 2020-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多