美文网首页程序员
国外优秀教程精译 | Swift 可选值详解(下)

国外优秀教程精译 | Swift 可选值详解(下)

作者: 溪石iOS | 来源:发表于2019-03-28 22:39 被阅读0次

    如果看完 Swift 可选值详解(上)后,你对可选值还是有些迷惑,甚至一头雾水,那么我们来换一种方式来解释。
    看下面的方法:

    func yearAlbumReleased(name: String) -> Int {
        if name == "Taylor Swift" { return 2006 }
        if name == "Fearless" { return 2008 }
        if name == "Speak Now" { return 2010 }
        if name == "Red" { return 2012 }
        if name == "1989" { return 2014 }
    
        return 0
    }
    

    该方法要求传入一个 Taylor Swift 专辑的名称,返回对应的发行年份。 但是如果我们传入了专辑名称“Lantern”,因为我们将 Taylor Swift 与 Hudson Mohawke 混为一谈(这是一个容易犯的错误,对吧?),该方法就返回 0,因为它不是 Taylor 的专辑之一。
    但 0 在这里有意义吗? 当然,如果专辑是在公元 0 年发布的,当时凯撒奥古斯是罗马的皇帝,0 可能有意义,但在这里只会让人感到困惑 —— 人们需要提前知道 0 的含义是“不被认可”。(译者注:这里说明的是,0 代表的含义需要提前定义,否者很容易被当作年份处理)
    最好是改写为返回 int (有对应年份时)或 nil (没有对应年份),可选值使这一切变得容易。下面是改写后的方法:

    func yearAlbumReleased(name: String) -> Int? {
        if name == "Taylor Swift" { return 2006 }
        if name == "Fearless" { return 2008 }
        if name == "Speak Now" { return 2010 }
        if name == "Red" { return 2012 }
        if name == "1989" { return 2014 }
    
        return nil
    }
    

    由于用了可选值,我们需要用 if let 解包,因为需要检查值是否存在。
    再来看另一种情形:

    var items = ["James", "John", "Sally"]
    

    现在我们想输出其中一个名字对应的索引值,我们可能这样写:

    func position(of string: String, in array: [String]) -> Int {
        for i in 0 ..< array.count {
            if array[i] == string {
                return i
            }
        }
    
        return 0
    }
    

    其中循环检查了数组成员,返回了对应名称的索引值,如果没找到,返回 0 。
    现在试着运行下面 4 行代码:

    let jamesPosition = position(of: "James", in: items)
    let johnPosition = position(of: "John", in: items)
    let sallyPosition = position(of: "Sally", in: items)
    let bobPosition = position(of: "Bob", in: items)
    

    将输出 0, 1, 2, 0 —— James 和 Bob 的位置是一样的,然而他们实际上一个存在,而另一个并不存在。这是因为我用 0 表示 “不存在” 造成的。图省事的话,可以用 -1 来表示不存在,但这样一来,又必须时刻记得有这个特殊值意味着“不存在”。(译者注:-1 引发的崩溃相信大家都有经历过,在 C 语言中,有符号 -1 转换为无符号时,为无符号的最大值,从而导致很多混乱)
    解决办法还是可选值:用 nil 表示没有找到对应名称。这也是数组内置查找方法 someArray.firstIndex(of: someValue)的实际做法。
    当你要对付“可能有可能没有”的值,Swfit 强制要求在使用前解包,以此明确这里可能没有值。if let就是用来做这个的:如果有值就解包后使用,否者完全不使用它。Swift 根本不让你凭空地使用一个可能为空的值。

    强制解包

    Swift 允许使用感叹号 !来屏蔽它的安全性。当你能确认可选值有值时,可以将感叹号放在这个值后面来强制解包它。

    请小心:如果你强制解包一个没有值的可选值时,会引发代码崩溃。

    下面是一些协同工作的代码:

    func yearAlbumReleased(name: String) -> Int? {
        if name == "Taylor Swift" { return 2006 }
        if name == "Fearless" { return 2008 }
        if name == "Speak Now" { return 2010 }
        if name == "Red" { return 2012 }
        if name == "1989" { return 2014 }
    
        return nil
    }
    
    var year = yearAlbumReleased(name: "Red")
    
    if year == nil {
        print("There was an error")
    } else {
        print("It was released in \(year)")
    }
    

    代码获得了专辑的发行年份。如果没找到专辑,year被置空,将打印出错信息。否则正确的发行年份会被打印。
    是吗?好吧,因为 yearAlbumReleased()返回的是可选值,这里由没有使用 if let来解包。结果,实际输出的是“It was released in Optional(2012)”——可能并不是我们想要的。
    关键是,我们已经检查了可选值的有效性,再用 if let进行所谓的安全解包显得有点无意义。因此,Swift 提供了解决办法——把上面代码中第二个print() 改为这样:

    print("It was released in \(year!)")
    

    注意这个感叹号:它的意思是“我保证这里有值,强制解包吧”。

    隐形解包

    你还能用感叹号来创建隐形解包可选值,这是很多人真正感到困惑的地方。那么就好好读读下面的介绍。

    • 静态变量必须含有值。比如:String 必须含有 string ,哪怕是空字符串"",不能为 nil 。
    • 可选值可以有值也可以没有。使用前必须解包。比如 String? 可能为 string ,或者是 nil ,确定的办法就是解包。
    • 隐形解包可选值可以有值也可以没有。但使用前不需要解包。Swift 不再为你检查,所以你使用时要额外小心。比如 String! 可能为 string ,或者是 nil ——取决于你适当的使用它。它类似静态变量,Swift 允许你直接访问它的值,不需要安全地解包。如果你要这么做,意味着你知道一定有值,否者程序会崩。

    使用隐形解包可选值的主要情形是在使用 UIKit 的界面元素时(macOS 里对应 AppKit ),这些需要事先声明,但是在创建之前你不能使用它们 —— 而 Apple 喜欢在最后一刻创建用户界面元素以避免任何不必要的工作。 必须不断地打开你肯定知道的值,这会使人厌烦,所以这些是隐式解开的。
    不要担心,如果您发现隐式解包的选项有点难以理解 - 当您使用该语言时,它将变得清晰。

    相关文章

      网友评论

        本文标题:国外优秀教程精译 | Swift 可选值详解(下)

        本文链接:https://www.haomeiwen.com/subject/wqyhbqtx.html