Swift使用guard和throws更優(yōu)雅的處理邏輯和錯(cuò)誤

代碼寫(xiě)多了就想優(yōu)化,這是一個(gè)天然的過(guò)程。近期在代碼優(yōu)化方面積累了一些心得,會(huì)慢慢整理出來(lái)。

本文主要適用于想要縮減代碼行數(shù)及規(guī)范化邏輯和錯(cuò)誤的場(chǎng)景。

首先回憶下在OC中是如何處理錯(cuò)誤和邏輯的,下面羅列兩種常見(jiàn)的處理方式。
1、方法定義返回值,根據(jù)返回值判斷成功還是失敗。復(fù)雜情況下定義枚舉可以覆蓋更多業(yè)務(wù)場(chǎng)景。

+ (BOOL) isFileExist:(NSString *)filePath
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL result = [fileManager fileExistsAtPath:filePath];
    return result;
}

2、通過(guò)NSError的指針寫(xiě)入,判斷NSError不為空獲取錯(cuò)誤信息。

NSError *error;
BOOL success = [data writeToFile: path options: options error: &error];
if(error) {
    // 發(fā)生了錯(cuò)誤
}

但實(shí)際情況是,很多時(shí)候不會(huì)出什么問(wèn)題,所以不少開(kāi)發(fā)會(huì)圖省事直接給error賦值nil。

下面介紹Swift中高逼格的用法。也就是關(guān)鍵字 throwsguard的應(yīng)用。

簡(jiǎn)單描述下例子場(chǎng)景:編寫(xiě)一個(gè)方法,通過(guò)Index獲取數(shù)組中的對(duì)象。
let item = array[index]
在一般情況下為了代碼可靠性和健壯性,會(huì)做一些非空判斷和邏輯判斷。根據(jù)返回值來(lái)絕對(duì)本次操作是否成功。

func getObjectByIndex(index:Int) -> Int {
        let array = [1,2,3,4,5]
        if index > 0{
            if array.count > 0{
                if index < array.count {
                    return array[index]
                }
            }
        }
        return -1
    }

這里有三層判斷,但在實(shí)際項(xiàng)目開(kāi)發(fā)中我見(jiàn)過(guò)10層以上的嵌套,以至于后面版本迭代邏輯時(shí)很容易挑錯(cuò)在哪個(gè)代碼塊里。

而且即使最后返回-1,誰(shuí)也不敢保證數(shù)據(jù)源里真的有一個(gè)合法的-1被正確的返回出來(lái)了。也許有人會(huì)想到定義枚舉來(lái)更細(xì)致的區(qū)分錯(cuò)誤,但這個(gè)例子中又和返回?cái)?shù)據(jù)沖突了。。。。

Swift中使用guard配合throws可以很便捷的解決這個(gè)問(wèn)題

guard的知識(shí)比較基礎(chǔ),已經(jīng)了解的同學(xué)可以跳過(guò)直接往下看。

先說(shuō)guard的用法,字面意思是守護(hù) 警衛(wèi)。

很形象的比喻:當(dāng)你走進(jìn)一個(gè)大門,門口一個(gè)警衛(wèi)站著,看你有問(wèn)題就攔下你,沒(méi)問(wèn)題就放你過(guò)去。

當(dāng)guard關(guān)鍵字后的表達(dá)式為false時(shí),就會(huì)執(zhí)行else后的代碼塊,否則就繼續(xù)往下執(zhí)行

//條件為true,else后的代碼塊不會(huì)執(zhí)行 
guard 1 == 1 else { return }
//條件為false,else后的代碼塊會(huì)執(zhí)行
guard 1 < 1 else { return }

很好理解不是么,熟練應(yīng)用后可以有效減少代碼的嵌套。

繼續(xù)改造上面的例子,首先定義一些錯(cuò)誤類型的枚舉。

    enum arrayError: Error {
        case indexCrossBoard, indexLessZero, arrayIsEmpty
    }

注:在Swift4.0中已經(jīng)取消了ErrorType關(guān)鍵字。目前統(tǒng)一繼承Error。

接下來(lái)在入?yún)⒑竺嬷屑尤?code>throws關(guān)鍵字標(biāo)記該方法,在方法體內(nèi)部使用throw拋出具體的錯(cuò)誤類型。

    func getObjByIndex(index:Int) throws -> Int {
        let array = [1,2,3,4,5]
        //when false,execute code in black after else
        guard index < array.count else { throw arrayError.indexCrossBoard }
        guard index > 0 else { throw arrayError.indexLessZero }
        guard array.count > 0 else { throw arrayError.arrayIsEmpty }
        
        return array[index]
    }

可以看到值返回和錯(cuò)誤返回已經(jīng)被區(qū)分開(kāi)了,當(dāng)一個(gè)方法體被throws關(guān)鍵字標(biāo)記后的方法代表它可能會(huì)向外拋出錯(cuò)誤,這個(gè)錯(cuò)誤可以是自定義的,可以取自上面自定義的枚舉。

有拋出就一定有接收,所以方法在被調(diào)用時(shí)會(huì)被強(qiáng)制加上do catch try關(guān)鍵字,不然編譯器會(huì)報(bào)錯(cuò)。

        do {
            let item:Int = try getObjByIndex(index: 20)
            
        } catch arrayError.indexCrossBoard {
            print("Error of Corss board")
        } catch arrayError.indexLessZero {
            print("Error of Index less Zero")
        } catch arrayError.arrayIsEmpty {
            print("Array is Empty")
        } catch {
            
        }

相比較傳統(tǒng)的NSError處理錯(cuò)誤,這樣的規(guī)范使得開(kāi)發(fā)無(wú)法漠視操作中可能會(huì)帶來(lái)的錯(cuò)誤。比如磁盤滿了,但任然嘗試寫(xiě)入文件,排查了半天又不知道哪里出問(wèn)題了,身邊又圍了很多QA和產(chǎn)品,你懂的。

而這種做法表面上看try catch一定程度上冗長(zhǎng)了代碼,但回想下我們之前處理不同的錯(cuò)誤類型不也是要嵌套很多if判斷來(lái)執(zhí)行不同操作么。所以代碼優(yōu)化只是一定程度上的規(guī)整和增加可讀性,該做的事還是少不了的。

以上是入門級(jí)用法,我們還可以嘗試進(jìn)行閉包拋出錯(cuò)誤。

    //Use throws mark Closure
    typealias ArrayErrorCallback = () throws -> Bool
    
    func checkObjectById(index:Int, errorBlock:@escaping (_ inner:ArrayErrorCallback) -> Void) {
        let array = [1,2,3,4,5]
        if index < array.count {
            // throw error
            errorBlock({ throw arrayError.indexCrossBoard })
        }
        // return value
        errorBlock({return true})
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        checkObjectById(index:20) { (inner: ArrayErrorCallback) -> Void in
            do {
                let success = try inner()
                print(success)
            } catch {
                print(error)
            }
        }
    }

用法差不多,只是把throws標(biāo)記在閉包上。更適合異步操作的場(chǎng)景。

基本就是這么多,大家可以回去翻閱下自己項(xiàng)目中的業(yè)務(wù)常見(jiàn),看哪些地方適合這樣的改動(dòng),本質(zhì)上還是以適合為主,不建議強(qiáng)行裝X。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容