[英]Swift if let evaluates successfully on Optional(nil)
I have a custom object called Field. 我有一个名为Field的自定义对象。 I basically use it to define a single field in a form.
我基本上用它来定义表单中的单个字段。
class Field {
var name: String
var value: Any?
// initializers here...
}
When the user submits the form, I validate each of the Field
objects to make sure they contain valid values. 当用户提交表单时,我验证每个
Field
对象以确保它们包含有效值。 Some fields aren't required so I sometimes deliberately set nil
to the value
property like this: 有些字段不是必需的,所以我有时会故意将
nil
设置为value
属性,如下所示:
field.value = nil
This seems to pose a problem when I use an if-let to determine whether a field is nil or not. 当我使用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.
}
I set breakpoints in the above if-else and when field.value
has been deliberately set to nil, it goes through the if-let block, not the else. 我在上面的if-else中设置了断点, 当
field.value
被故意设置为nil时,它会通过if-let块,而不是else。 However, for the fields whose field.value
I left uninitialized and unassigned, the program goes to the else block. 但是,对于
field.value
我保持未初始化和未分配的字段, 程序将转到else块。
I tried printing out field.value
and value
inside the if-let block: 我尝试在if-let块中打印出
field.value
和value
:
if let value = field.value {
NSLog("field.value: \(field.value), value: \(value)")
}
And this is what I get: 这就是我得到的:
field.value: Optional(nil), value: nil
field.value:可选(零),值:nil
So I thought that maybe with optionals, it's one thing to be uninitialized and another to have the value of nil. 所以我认为可能有选择性,未初始化是一回事而另一个是nil的价值。 But even adding another if inside the if-let won't make the compiler happy:
但即使在if-let中添加另一个也不会让编译器满意:
if let value = field.value {
if value == nil { // Cannot invoke '==' with an argument list of type '(Any, NilLiteralConvertible)'
}
}
How do I get around this? 我该如何解决这个问题? I just want to check if the
field.value
is nil
. 我只是想检查
field.value
是否nil
。
I believe this is because Any?
我相信这是因为
Any?
allows any value and Optional.None
is being interpreted as just another value, since Optional
is an enum! 允许任何值和
Optional.None
被解释为另一个值,因为Optional
是一个枚举!
AnyObject?
should be unable to do this since it only can contain Optional.Some([any class object])
, which does not allow for the case Optional.Some(Optional)
with the value Optional.None
. 应该无法执行此操作,因为它只能包含
Optional.Some([any class object])
,这不允许使用值Optional.None
Optional.Some(Optional)
大小写。
This is deeply confusing to even talk about. 甚至谈论这都令人深感困惑。 The point is: try
AnyObject?
关键是:尝试
AnyObject?
instead of Any?
而不是
Any?
and see if that works. 并看看是否有效。
More to the point, one of Matt's comment mentions that the reason he wants to use Any
is for a selection that could be either a field for text input or a field intended to select a Core Data object. 更重要的是,Matt的评论之一提到他想要使用
Any
的原因是选择可以是文本输入字段或用于选择Core Data对象的字段。
The Swifty thing to do in this case is to use an enum with associated values , basically the same thing as a tagged/discriminated union . 在这种情况下要做的Swifty事情是使用带有关联值的枚举 ,基本上与标记/区分联合相同 。 Here's how to declare, assign and use such an enum:
以下是如何声明,分配和使用这样的枚举:
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
}
}
Using an enum like this, there's no need to worry about which things could be hiding inside that Any?
使用这样的枚举,没有必要担心哪些内容可能隐藏在
Any?
. 。 There are two cases and they are documented.
有两种情况,它们都有记录。 And of course, the selection variable can be an optional without any worries.
当然,选择变量可以是可选的而不用担心。
There's a tip to replace my Any?
有一个提示可以替换我的
Any?
type with an enum but I couldn't get this error out of my head. 用枚举键入,但我无法从头脑中得到这个错误。 Changing my approach doesn't change the fact that something is wrong with my current one and I had to figure out how I arrived at an
Optional(nil)
output. 改变我的方法并没有改变我当前的方法出错的事实,我不得不弄清楚我是如何得到一个
Optional(nil)
输出。
I was able to reproduce the error by writing the following view controller in a new single-view project. 通过在新的单视图项目中编写以下视图控制器,我能够重现错误。 Notice the
init
signature. 注意
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)")
}
}
In short, I was passing a nil value ( AppState().currentValue
) to an initializer that accepts Any
, and assigns it to a property whose type is Any?
简而言之,我将nil值(
AppState().currentValue
)传递给接受Any
的初始值设定项,并将其分配给类型为Any?
的属性Any?
. 。 The funny thing here is if I directly passed
nil
instead, the compiler will complain: 这里有趣的是,如果我直接传递
nil
,编译器会抱怨:
let f = Field("Amount", nil) // Type 'Any' does not conform to protocol 'NilLiteralConvertible'
It seems that somewhere along the way, Swift wraps the nil
value of AppState().currentValue
in an optional, hence Optional(nil)
. 似乎在某个地方,Swift将
AppState().currentValue
的nil
值包含在一个可选的,因此是Optional(nil)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.