美文网首页程序员iOS Developer
【iOS 开发】想一下再用 guard

【iOS 开发】想一下再用 guard

作者: KyXu | 来源:发表于2016-07-18 16:30 被阅读786次

    自从知道了 <code>guard let</code> 这种写法之后,我就几乎换掉了所有 <code>if let</code> 写法。但今天要提醒一下,使用 <code>guard let</code> 之前,需要先思考一下,因为这并不总是万全的解放方案。

    // bad
    func createMan0(name: String?, country: String?, age: Int?) -> Man? {
        if let name = name {
            if let country = country {
                if let age = age {
                    return Man(name: name, country: country, age: age)
                }
            }
        }
        return nil
    }
    
    // good
    func createMan1(name: String?, country: String?, age: Int?) -> Man? {
        guard let name = name else { return nil }
        guard let country = country else { return nil }
        guard let age = age else { return nil }
        return Man(name: name, country: country, age: age)
    }
    

    如上的代码是很常见的 <code>guard let</code> 使用场景,为了避免让我们写出 “Swift 鞭尸金字塔”。

    enum NetworkState {
        case Cellular
        case Wifi
    }
    
    func test(state:NetworkState) {
        switch state {
        case .Cellular:
            guard let speed = networkSpeed else {return}
            print("Cellular Speed: \(speed)")
        case .Wifi:
            guard let speed = networkSpeed else {return}
            print("Wifi Speed: \(speed)")
        }
        // 可能无法被执行
        doSomething()
    }
    
    test(.Cellular)
    

    但这种情况下,如果我们一看到 <code>networkSpeed</code> 是可选型的,就决定使用 <code>guard ... else {return}</code> 语法,那么会出现的结果就是一旦 <code>networkSpeed</code> 值为 <code>nil</code> , <code>doSomething()</code> 将不会被执行。我们一开始可能仅仅是希望无法获取网速数值的时候,不在控制台打印相应信息,但现在整个 <code>test()</code> 都被提前退出了。解决这个问题很简单,把 <code>guard ... else {return}</code> 改成 <code>guard ... else {break}</code>,让 <code>switch - case</code> 里面的代码段提前退出就可以了。

    但是并不一定每种情况我们都要回避使用 <code>guard ... else {return}</code>

    enum File {
        case Pages
        case Keynote
    }
    
    func saveInBackground( completion: File->Void ) {
        completion(.Pages)
    }
    
    func closureTest() {
        saveInBackground( { file in
            switch file {
            case .Pages:
                guard let name = fileName else {return}
                print("Pages: \(name)")
            case .Keynote:
                guard let name = fileName else {return}
                print("Keynote: \(name)")
            }
        })
        // 一定会被执行
        doSomething()
    }
    
    closureTest()
    

    这种情况下,<code>return</code> 所退出的方法是 <code>saveInBackground</code> 函数里面的闭包 <code>completion: File->Void</code>,<code>saveInBackground</code> 本身不受影响,如果 <code>saveInBackground</code> 里面还有其他参数是闭包,那么其他闭包自然也不受影响。

    func configureButton(button:UIButton, buttonTitle:String?, buttonImage:UIImage?) {
        if let title = buttonTitle {
            button.setTitle(title, forState: .Normal)
        }
        if let image = buttonImage {
            button.setImage(image, forState: .Normal)
        }
    }
    

    而在这种情况,<code>if let</code> 语法就很自然,有 title 我们就设置 title,有 image 我们就设置 image,没有就算了,总不能说没有 title 或 image 就直接放弃当前的方法,或许我们后面还要做很多其他事情。


    没东西了

    希望大家在使用 <code>guard</code> 关键字的时候多思考一下,以免犯下低级错误。

    相关文章

      网友评论

        本文标题:【iOS 开发】想一下再用 guard

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