【问题标题】:Forced unwrapping vs not强制解包 vs 不解包
【发布时间】:2014-06-13 14:36:44
【问题描述】:

Facebook 最近更新了 Parse 以支持 Swift。它给出的代码示例之一是这样的:

var gameScore = PFObject(className: "GameScore")
gameScore.setObject(1337, forKey: "score")
gameScore.setObject("Sean Plott", forKey: "playerName")
gameScore.saveInBackgroundWithBlock { 
(success: Bool!, error: NSError!) -> Void in
    if success {
        NSLog("Object created with id: \(gameScore.objectId)")
    } else {
        NSLog("%@", error)
    }
}

我对这部分很好奇:“(success: Bool!, error: NSError!)”,尤其是感叹号。我对可选项的理解是这样的:

NSError:这是一个 NSError,不能为 nil。 NSError?: 这可能包括一个 NSError 或者它可能是 nil,但它需要首先被解包。 NSError!: 这是一个强制解包的 NSError?,因此不能为 nil。

Facebook 的例子说成功是一个布尔值!并且错误是一个NSError! - 即,它们都是绝对提供的。为什么它们不只是写成 Bool 和 NSError,如果 Facebook 在发送它们之前已经解开它们?另外,如何同时设置成功和错误? NSError 的传统用法是在没有问题的情况下将其设置为 nil。

【问题讨论】:

  • ! 是一个隐式解包的可选项,其行为完全类似于可选项,只是您可以访问属性,而必须事先解包。不利的一面是,如果你这样做并且它的nil,你会得到一个例外
  • 当您看到一个非可选参数 (!) 时,这正是其名称所暗示的含义:您始终可以假定它是一个有效对象,并且在任何时候都不会是 nil你的块被调用了。

标签: swift


【解决方案1】:

这可能是由于与 Objective-C API 的互操作性。由于在 Objective-C 中任何对象都可以是 nil,因此这两个值在 Swift 中必须是可选的。

无论如何 - 因为显然他们保证这些对象永远不会是 nil - 他们可以隐式地解包它们,允许使用此 API 的人保存一些解包,这很好。

关于你的陈述

NSError 的传统用法是在没有问题时将其设置为 nil。

这是错误的,即使在 Objective-C 中也是如此。

Cocoa 中的BOOL/NSError 模式要求您必须检查success 的值以了解是否发生了错误,并且 - 如果是这种情况 - 那么NSError 将包含有关它的信息。

检查NSError 是否为nil 是这种模式的常见误用,它可能导致代码中的逻辑错误,因为即使成功,某些Apple API 也会返回非nil 错误。

【讨论】:

  • 是的,我想知道这是否只是互操作的原因。我正在尝试考虑清楚:那么公平地说,进行此回调的 ObjC 方法可以传入 nil(因为它只是传入标准 NSObjects),因此连接两者的运行时部分将认为它们是可选的参数,所以 Facebook 代码为了方便开发人员而强制解包它们?
  • 另外,你说得对,我的措辞很差。我并不是要检查 nil 并忽略成功,这确实是一件坏事。我的意思是,如果调用成功,我希望 error 为零。在 Facebook 的情况下,如果调用成功,error 怎么可能是 not-nil?
  • @FizzBu​​zz,将 error 想象成不是错误,而更像是 status report。 “成功”报告也是报告,逻辑上与“错误”或“警告”相同。 “成功”报告通常为零 (0) error-code,这是完全有效的错误 no-error
  • Obj-C 在技术上可以通过nil,因为没有正式的方法可以阻止它。他们强制展开的事实意味着他们知道这不会是由实现引起的。这是您根本无法用 Obj-C 表达的正式保证。关于非零错误,它可以简单地是一个带有“ok”代码的NSError 实例(如0 或类似的)
【解决方案2】:

Facebook 的例子说成功是一个布尔值!并且错误是一个NSError! - 即,它们都是肯定提供的。

是的,他们是。请记住,错误代码 0 (0) 通常标志着交易成功,这在逻辑上比发送 nil 更正确。

另外,如何同时设置成功和错误? NSError 的传统用法是在没有问题的情况下将其设置为 nil。

告诉您(隐含地),如果发生任何错误,error始终作为有效的错误消息提供给您的块。

【讨论】:

  • 它还告诉你error在任何情况下都是总是提供的。
  • 显然,是的,这是真的。但通常如果交易成功,即使提供了错误消息,您也会忽略错误消息。
  • 同意这是常见的模式,但保证远非显而易见。没有错误发生时通常是nil
  • 是的,我知道。但是在这里,为什么错误根本不应该是可选的,这似乎要好得多;想象一下相反的情况,当错误在这里是可选的时,你不能自动确定error 是有效的对象,当事务失败时,这比有一个更糟糕的情况(逻辑上 - 在我看来) extra' 成功时的错误对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-19
  • 2016-07-13
  • 2017-01-20
  • 1970-01-01
相关资源
最近更新 更多