Swift如果让评估成功可选(无)

我有一个名为Field的自定义对象。 我基本上用它来定义一个窗体中的单个字段。

class Field { var name: String var value: Any? // initializers here... } 

当用户提交表单时,我validation每个Field对象以确保它们包含有效的值。 有些字段不是必需的,所以我有时故意将nil设置为value属性,如下所示:

 field.value = nil 

这似乎是一个问题,当我使用if-let来确定一个字段是否为零。

 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.valuevalue

 if let value = field.value { NSLog("field.value: \(field.value), value: \(value)") } 

这就是我得到的:

field.value:可选(nil),值:nil

所以我认为,也许用可选项,未初始化是另一回事,有零的价值。 但是,即使在if-let内部添加另一个也不会使编译器感到高兴:

 if let value = field.value { if value == nil { // Cannot invoke '==' with an argument list of type '(Any, NilLiteralConvertible)' } } 

我如何解决这个问题? 我只是想检查field.value是否nil

我相信这是因为Any? 允许任何值和Optional.None被解释为只是另一个值,因为Optional是一个枚举!

AnyObject? 应该无法执行此操作,因为它只能包含Optional.Some([any class object]) ,它不允许使用Optional.Some(Optional) ,其值为Optional.None

这甚至令人困惑,甚至谈论。 重点是:尝试AnyObject? 而不是Any? 看看是否有效。


更重要的是,Matt的评论之一提到,他想使用Any的原因是用于select文本input的字段或用于select核心数据对象的字段。

在这种情况下要做的Swifty事情是使用一个枚举与关联的值 ,基本上是一样的东西作为标记/歧视的联盟 。 以下是如何声明,分配和使用这样的枚举:

 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? 。 有两种情况,他们被logging在案。 当然,selectvariables可以是可选的,不用担心。

有一个技巧来取代我的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)") } } 

简而言之,我将一个零值( AppState().currentValue )传递给接受Any的初始化程序,并将其赋值给Any?types的属性Any? 。 这里有趣的是如果我直接通过nil ,编译器会抱怨:

 let f = Field("Amount", nil) // Type 'Any' does not conform to protocol 'NilLiteralConvertible' 

似乎在某个地方,Swift将AppState().currentValuenil值封装在一个可选的, Optional(nil)