我有一个名为Field的自定义对象。我基本上用它来定义表单中的单个字段。
class Field {
var name: String
var value: Any?
// initializers here...
}
当用户提交表单时,我验证每个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.value
和value
:
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
。
答案 0 :(得分:3)
我认为这是因为Any?
允许任何值,Optional.None
被解释为另一个值,因为Optional
是一个枚举!
AnyObject?
应该无法执行此操作,因为它只能包含Optional.Some([any class object])
,这不允许案例Optional.Some(Optional)
的值为Optional.None
。
即使谈论这也令人深感困惑。重点是:尝试AnyObject?
而不是Any?
,看看是否有效。
更重要的是,Matt的一条评论提到他想要使用Any
的原因是选择可以是文本输入的字段,也可以是用于选择Core Data对象的字段。< / p>
在这种情况下要做的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?
内。有两种情况,它们都有记录。当然,选择变量可以是一个可选项而不用担心。
答案 1 :(得分:0)
有一个提示用枚举替换我的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?
的属性。这里有趣的是,如果我直接通过nil
,编译器会抱怨:
let f = Field("Amount", nil) // Type 'Any' does not conform to protocol 'NilLiteralConvertible'
似乎在某个地方,Swift将nil
的{{1}}值包含在一个可选项中,因此AppState().currentValue
。