检查Swift字典扩展中的nil值

时间:2016-03-15 17:33:06

标签: swift dictionary null extension-methods optional

我在一个操场文件中有以下代码:

extension Dictionary {

    func test()  {

        for key in self.keys {
            self[key]
        }
    }
}

var dict: [String: AnyObject?] = [
    "test": nil
]

dict.test()

我今后将把for-each循环中的行称为输出,因为它是相关的。在此特定实例中,输出为nil

当我将for-each循环更改为如下所示:

for key in self.keys {
    print(self[key])
}

输出为"Optional(nil)\n"

我真正想做的是检查nil的值,但是代码:

for key in self.keys {
    self[key] == nil
}

输出false

我尝试的另一件事是:

for key in self.keys {
    self[key] as! AnyObject? == nil
}

产生错误:

Could not cast value of type 'Swift.Optional<Swift.AnyObject>' to 'Swift.AnyObject'

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:7)

你已经弄得一团糟了,因为一个值为nil的词典可以让你看到双包裹的可选的前景,因此有两种{ {1}}。如果密钥丢失,则会获得nil,如果密钥,则会获得nil并解包所获取的结果。不幸的是,你正在一个操场上进行测试,这是一个探索这种区别的糟糕场所。

要明白我的意思,请考虑以下几点:

nil

var d : [String:Int?] = ["Matt":1] let val = d["Matt"] 的类型是什么?它是val - 包含在另一个Optional中包含的可选的Int。这是因为根据定义, in 字典中的值是包含在Optional中的Int,然后通过其键获取值包装在 another Optional中。

现在让我们再进一步,这样做:

Int??

什么是var d : [String:Int?] = ["Matt":nil] let val = d["Matt"] ?好吧,操场可能它是val,但事实更复杂;它是nil 包装在另一个可选中。如果你打印 nil,这是最容易看到的,在这种情况下,你得到的不是val,而是nil

但是如果我们尝试一下根本没有关键的东西,我们会得到一个不同的答案

"Optional(nil)"

真的 let val2 = d["Alex"] ,表示密钥丢失了。如果我们打印 nil,我们会得到val2。操场未能区分("nil"nil都显示val,但转换为字符串(val2所做的)显示差异。

问题的一部分是整个双重包装的可选事物,另一部分是Playground以非常误导的方式表示双重包装的选项。

MORAL 1 :值类型为Optional的字典可能会非常棘手。

道德2 :游乐场是魔鬼的作品。避免他们。使用真实应用程序,并使用日志记录到控制台或调试器的变量窗格,以查看实际发生的情况。

答案 1 :(得分:3)

检查词典值nil是否有意义 字典值是Optional类型,这意味着你必须这样做 将您的扩展方法限制为该情况。

这可以通过定义所有可选类型符合的协议来实现 to(比较How can I write a function that will unwrap a generic property in swift assuming it is an optional type?,这只是Creating an extension to filter nils from an Array in Swift的略微修改):

protocol OptionalType {  
    typealias Wrapped 
    var asOptional : Wrapped? { get }
}  

extension Optional : OptionalType {  
    var asOptional : Wrapped? {  
        return self 
    }  
}

现在您可以定义一个限制为的扩展方法 可选值类型的字典:

extension Dictionary where Value : OptionalType {

    func test()  {
        for key in self.keys { ... }
    }
}

正如马特已经解释的那样,self[key]只有nil才能获得该密钥 在字典中缺少,这不可能发生在这里。那么你 总是可以检索该键的值

            let value = self[key]! 

在那个循环里面。更好,枚举键和值:

        for (key, value) in self { ... }

现在value是字典值(对于key)及其类型 符合OptionalType。使用asOptional协议属性 你得到一个可选的,可以针对nil进行测试:

             if value.asOptional == nil { ... }

或与可选绑定一起使用。

把所有这些放在一起:

extension Dictionary where Value : OptionalType {

    func test()  {
        for (key, value) in self {
            if let unwrappedValue = value.asOptional {
                print("Unwrapped value for '\(key)' is '\(unwrappedValue)'")
            } else {
                print("Value for '\(key)' is nil")
            }
        }
    }
}

示例:

var dict: [String: AnyObject?] = [
    "foo" : "bar",
    "test": nil
]

dict.test()

输出:

Value for 'test' is nil
Unwrapped value for 'foo' is 'bar'