Swift if let 在 Optional(nil) 上成功评估
Posted
技术标签:
【中文标题】Swift if let 在 Optional(nil) 上成功评估【英文标题】:Swift if let evaluates successfully on Optional(nil) 【发布时间】:2014-09-16 08:11:19 【问题描述】:我有一个名为 Field 的自定义对象。我基本上用它来定义表单中的单个字段。
class Field
var name: String
var value: Any?
// initializers here...
当用户提交表单时,我会验证每个 Field
对象以确保它们包含有效值。有些字段不是必需的,所以我有时故意将nil
设置为value
属性,如下所示:
field.value = nil
当我使用 if-let 来确定字段是否为 nil 时,这似乎会造成问题。
if let value = field.value
// The field has a value, ignore it...
else
// Add field.name to the missing fields array. Later, show the
// missing fields in a dialog.
我在上面的 if-else 中设置了断点,当 field.value
被故意设置为 nil 时,它会通过 if-let 块,而不是 else。 但是,对于那些field.value
我未初始化和未分配,程序转到 else 块。
我尝试在 if-let 块内打印出 field.value
和 value
:
if let value = field.value
NSLog("field.value: \(field.value), value: \(value)")
这就是我得到的:
field.value:可选(nil),值:nil
所以我认为,也许对于可选项,未初始化是一回事,而值为 nil 则是另一回事。但即使在 if-let 中添加另一个 if 也不会让编译器满意:
if let value = field.value
if value == nil // Cannot invoke '==' with an argument list of type '(Any, NilLiteralConvertible)'
我该如何解决这个问题?我只想检查field.value
是否为nil
。
【问题讨论】:
无法复制。您使用哪个 Xcode 版本? Xcode 6 通用。尝试重新启动它,仍然没有运气。 :( 您能否发布一个完整的独立示例来演示该问题? 不要试图使用Any
。通过使用Any
,你放弃了一半的 Swift 特性(强类型)。为什么不在那里使用一个不错的泛型类型?
@MattQuiros:所以使用具有两种情况的枚举:case CoreDataObject(NSManagedObject)
和 case StringField(String)
,然后使用该枚举的可选类型而不是 Any?
。
【参考方案1】:
我相信这是因为Any?
允许任何值,而Optional.None
被解释为另一个值,因为Optional
是一个枚举!
AnyObject?
应该无法做到这一点,因为它只能包含Optional.Some([any class object])
,这不允许Optional.Some(Optional)
的值Optional.None
。
这甚至说起来都令人深感困惑。重点是:尝试AnyObject?
而不是Any?
看看是否可行。
更重要的是,Matt 的一条评论提到,他想要使用 Any
的原因是为了选择可能是文本输入字段或旨在选择核心数据对象的字段。
在这种情况下,Swifty 要做的事情是使用enum with associated values,与tagged/discriminated union 基本相同。以下是如何声明、分配和使用此类枚举:
enum DataSelection
case CoreDataObject(NSManagedObject)
case StringField(String)
var selection : DataSelection?
selection = .CoreDataObject(someManagedObject)
if let sel = selection // if there's a selection at all
switch sel
case .CoreDataObject(let coreDataObj):
// do what you will with coreDataObj
case .StringField(let string):
// do what you will with string
使用这样的枚举,无需担心Any?
中可能隐藏了哪些内容。有两种情况,并记录在案。当然,选择变量可以是可选的,不用担心。
【讨论】:
正确答案是“不惜一切代价避免Any
”。如果你使用可选的Any
,你就完蛋了。
是的,因为语言似乎没有办法区分 Optional.None
是用作实际值还是在可选 Any
中标记值的缺失。 【参考方案2】:
有一个提示可以用枚举替换我的 Any?
类型,但我无法摆脱这个错误。改变我的方法并不能改变我当前的方法有问题的事实,我必须弄清楚我是如何得出Optional(nil)
输出的。
通过在新的单视图项目中编写以下视图控制器,我能够重现该错误。注意init
签名。
import UIKit
class Field
var name: String = "Name"
var value: Any?
init(_ name: String, _ value: Any)
self.name = name
self.value = value
class AppState
var currentValue: Field?
class ViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
let f = Field("Amount", AppState().currentValue)
NSLog("\(f.value)")
简而言之,我将 nil 值 (AppState().currentValue
) 传递给接受 Any
的初始化程序,并将其分配给类型为 Any?
的属性。有趣的是,如果我直接传递nil
,编译器会报错:
let f = Field("Amount", nil) // Type 'Any' does not conform to protocol 'NilLiteralConvertible'
似乎在路上的某个地方,Swift 将 AppState().currentValue
的 nil
值包装在一个可选项中,因此是 Optional(nil)
。
【讨论】:
nil
不作为值存在(仅作为关键字),但 Optional.None
是任何可选变量的默认值,当被要求描述自身时,它会打印 nil
。
以上是关于Swift if let 在 Optional(nil) 上成功评估的主要内容,如果未能解决你的问题,请参考以下文章