Swifter 100 tips 讀后總結

Swifter 100 tips 讀后總結

  1. 將protocol的方法2為mutating,原因如下:

    1. protocol也適用于struct和enum中,如果不添加mutating,那么在struct和enum中將會提示沒有實現協議方法,無法通過編譯.
    2. 如果去掉protocol中的mutating字段,那么struct和中將會報錯說不能改變成員變量.
    3. 在class 中實現protocol 方法的時候,不需要添加mutating字段,因為class可以隨意更改自己的成員變量,所以在protocol里邊用mutating修飾方法,對于class的實現是完全透明的,可以當做不存在.
  2. 多元組 (Tuple)

    這是一個oc中沒有使用過的結合類型,使用它可以幫助我們簡化很多問題,比如:

    1. 在oc甚至java中,交換2個變量的值,我們通常會這么寫:
    func swapMel<T>(a: inout T, b: inOut T) {
         let temp = a
         a = b
         b = temp
    }
    

    這樣做很容易理解,但是產生了一個中間變量,這是我們不想看到的結果,所以有人會這么寫:

    func swapMel<T>(a: inOut T, b: inOut T) {
         a = a ^ b
         b = b ^ a
         a = a ^ b
    }
    

    這樣,我們就沒有新增一個中間變量,就進行了2個變量的值的交換,但是這樣做的代價就是不容易理解.當我們用swift中的Tuple來實現就簡單多了,并且很容易理解:

    func swapMel<T>(a: inOut T, b: inOut T) {
         (a, b) = (b, a)
    }
    

    這樣我們就完成了2個變量的交換過程,很簡單.

    1. oc中的返回值只能有一個,所以在解決某些問題的時候會顯得很麻煩,比如:

    CGRect有一個輔助方法CGRectDivide,它是將一個CGRect在一定位置切分成2個區域,具體使用方法如下:

    CGRect rect = CGRectMake(0, 0, 100, 100);
    CGRect small;
    CGRect large;
    CGRectDivide(rect, &small, &large, 20, CGRectMinXEdge);
    

    它將{0, 0, 100, 100}分割成了small:{0, 0, 20, 100} 和 large: {20, 0, 80, 100} 2個區域,

    下邊我們可以用swift的Tuple來實現,并對比一下:

    extension CGRect {
         func divided(atDistance: CGFload, from fromEdge: CGRectEdge) -> (slice: CGRect, remainder: CGRect) {
             //...
         }
    }
    

    使用的時候,做法如下:

    let rect = CGRect(x: 0, y: 0, width: 100, height: 100)
    let (small, large) = rect.divided(atDistance: 20, from: .minXEdge)
    

    這樣看起來就很簡單明了

  3. @autoclosure 和 ??

    1. @autoclosure做的事情就是吧一句表達式自動封裝成一個閉包(closure).

    比如我們有一個方法接受一個閉包參數,當閉包執行結果為true的時候進行打印:

    func logIfTrue(_ predicate: () -> Bool) {
         if predicate() {
             print("True")
         }
    }
    

    在調用的時候,我們會這樣寫:

    logIfTrue({return 2 > 1})
    

    swift中對閉包的寫法進行了一些簡化,當只有一條return語句的時候,我們可以這樣寫:

    logIfTrue({2 > 1})
    

    因為這個閉包是logIfTrue函數的最后一個參數,也就是尾隨閉包,所以我們還可以簡寫如下:

    logIfTrue{2 > 1}
    

    猶豫簡寫的過多,這樣看起來其實已經不那么好理解了,這時候我們就可以使用@autoclosure:

    func logIfTrue(_ predicate: @autoclosure () -> Bool) {
         if predicate() {
             print("True")
         }
    }
    

    這時候我們就可以直接寫:

    logIfTrue(2 > 1)
    

    他會自動把 2 > 1這個表達式轉換成 () -> Bool,這樣我么就得到一個寫法簡單,表意清除的式子.

    1. ??

    ?? 使用來快速判斷nil的.語意是:如果??操作符左邊的值是非nil的Optional值,就返回他的value,如果是nil,就有??操作符右邊的值代替,比如:

    var level: Int?
    var startLevel = 1
    
    var currentLevel = level ?? startLevel
    

    注意:@autoclosure并不支持帶有輸入參數的方法,也就是形如() -> T的參數才能使用這個特性進行簡化.

    // ?? 的2中形式和底層實現
    func ??<T>(optional: T?, defaultValue: @autoclosure () -> T?) -> T?
    func ??<T>(optional: T?, defaultValue: @autoclosure () -> T) -> T
    // 我們之前用到的是第二種
    func ??<T>(optional: T?, defaultValue: @autoclosure () -> T) -> T {
         switch optinal {
             case .Some(let value):
                 return value
             case .None:
                 return defaultValue()
         }
    }
    

    有人可以會對為什么使用@autoclosure有疑問,說不使用閉包,直接賦值不好嗎? 原因是這樣的,這個默認值可能是經過特別復雜的計算獲得的,但是它只有在??左側為nil的時候才用的到,當??左側非nil的時候我們根本用不到,所以就不用計算這個默認值,我們通過這個閉包,就可以把默認值的計算推遲到optional判定為nil之后,這就是巧妙之處.

    另外,swift中的&& 和||操作符其實也用到了@autoclosure

  4. Optional Chaining

    使用Optional Chaining可以讓我們拜托很多不必要的判斷和取值,但是使用的時候要小心,還是有坑的

    因為Optional Chaining是隨時都可能提前返回nil的,所以使用Optional Chaining所得到的東西其實都是Optional的,比如下邊一段代碼:

    class Toy {
        let name: String
        init(name: String) {
            self.name = name
        }
    }
    
    class Pet {
        var toy: Toy?
    }
    
    class Child {
        var pet: Pet?
    }
    

    在實際使用中,當我們想要知道小明的寵物的玩具的名字的時候,可以通過Optional Chaining來拿到:

    let toyName = xiaoming.pet?.toy?.name
    

    雖然我們訪問的是name,并且Toy中name被定義為一個確定的String,而不是String?, 但我們拿到的toyName其實還是String?類型.因為在Optional Chaining中隨時可能會遇到nil而提前返回,這個時候我們拿到的就是nil了.

    然而,實際使用中,我們通常會通過Optional Binding(可選綁定)來取值這樣的代碼:

    if let toyName = xiaoming.pet?.toy?.name {
         // 這時候拿到的toyName必然不是nil
    }
    

    單獨這樣看還是很清楚的,如果和其他的特性結合在一起,可能就會很麻煩了:

    // 給Toy添加一個extension
    // 當 child 的pet 有toy的時候就玩,沒有就不能玩
    extension Toy {
        func play() {
            // ...
        }
    }
    

    拿小明舉例子, 如果小明的pet有toy的話,就玩之:

    xiaoming.pet?toy?.play()
    

    如果現在除了小明還有小李小張等,我們需要把這一串調通抽象出來,做一個閉包方便使用.傳入一個child對象,于是我們就可能寫成下邊這個樣子:

    這是錯誤的代碼:

    let playClosure = {(child: Child) -> () in
     child.pet?.toy?play()
    }
    

    這樣的代碼是沒有意義的!可能有人會問,問題處在那里呢?

    問題就在play()的調用上.定義的時候沒有寫play()的返回值,就是Void(同()是等價的),但是經過前面的Optional Chaining以后,我們拿到的是一個Optional的結果,也就是我們最后得到的應該是一個closure:

    let playClosure = {(child: Child) -> ()? in
     child.pet?.toy?play()
    }
    

    這樣調用的返回將是一個()?(等同于Void?),雖然看起來很奇怪,但這是事實.使用的時候,我們通過Optional Binding來判定方法是否調用成功:

    if let result: () = playClosure(xiaoming) {
         print("happy")
    } else {
         print("no toy")
    }
    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容