Swift如果让我们成功评估Optional(nil)

时间:2014-09-16 08:11:20

标签: ios cocoa cocoa-touch swift optional

我有一个名为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.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

2 个答案:

答案 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