1. 程式人生 > >Swift中由找不到removeAll(where:)方法引起的連鎖反應(上)

Swift中由找不到removeAll(where:)方法引起的連鎖反應(上)

提示:本篇博文涉及到第三方庫Eureka,但核心思想在於Swift內部資料處理的推斷,不瞭解Eureka並不影響對本文的理解。Eureka只不過是對UITableView的便捷包裝而已,需要進一步瞭解Eureka的童鞋可以觀賞本貓Eureka學習系列博文。

核心程式碼

section.removeAll {baseRow in
    if let habitRow = baseRow as? HabitRow{
        let idxPath = habitRow.indexPath!
        return willRemoveIdxPaths.contains(idxPath)
    }
    return false
}

以上程式碼片段的功能是刪除willRemoveIdxPaths佇列中對應的所有Rows。Row對應著一個Cell,Cell是Eureka中對UITableViewCell的包裝。那麼上面實際是將指定的Cells從UITableView中刪除。

核心問題

為什麼要用removeAll(where:)方法去刪除Rows,而不是用遍歷刪除的方法?比如說如下程式碼:

for idxPath in willRemoveIdxPaths{
	section.remove(at: idxPath.row)
}

原因是:遍歷刪除的方法在刪除多個Row時行為並不正確!

道理很簡單,當刪除掉一個Row後,其他Row的索引會發生變化,那麼其他待刪除的索引就會指向錯誤的Row。

舉個栗子:比如我要一次性刪除0和1位置兩個Row,但是當我刪除掉0位置的Row後,原來1位置的Row會上升到位置0,原來2位置的Row會上升到位置1;接下來我再刪除位置1的Row,實際刪除的卻是原來位置2的Row。

那麼問題又來了:為什麼removeAll(where:)可以正確刪除多個Row?

這個答案先不揭曉,它會隨著本貓的敘述逐漸明朗,現在暫且相信本貓它可以滿足一次性刪除多個Row的功能。

使用場景一 :Xcode 10+ Swift 4.2

刪除程式碼工作良好

使用場景二 :Xcode 9.2 Swift 4.1

提示找不到removeAll(where:)方法!!!
提示找不到removeAll(where:)方法!!!
提示找不到removeAll(where:)方法!!!

但是removeAll()方法是存在的!

在這裡插入圖片描述

為了能夠更好地解釋為什麼找不到這個方法,我們首先要搞清楚,這個方法是從哪裡來的?

線索一 removeAll(where:) Where Are You From???

為了方便討論,直接看搜尋結果

在這裡插入圖片描述
在這裡插入圖片描述

從上面我們瞭解到2點:

  1. 該方法只在Xcode 10.0+才可以使用
  2. 該方法是RangeReplaceableCollection協議的一部分

這是一個好的開頭,不是麼?(這是原創文章,雖然這段話很像翻譯的…)

線索二 Section到底是什麼?為什麼包含removeAll方法?

因為Eureka是開源的,所以這個問題的答案頗為簡單:它幾乎什麼都不是!

它不繼承於任何類,包含的所有Row或Cell你幾乎都不能直接操作;它內部實現了一個KVOWrapper類,用於處理Row各種修改的細節。

那麼問題又來了:它為什麼可以有removeAll或removeAll(where:)方法?

從線索一中不難推斷答案:因為它遵守RangeReplaceableCollection協議!

所以它包含集合操作的N種方法:

在這裡插入圖片描述

看到這大家都應該明瞭:

Xcode 9.2中之所以找不到removeAll(where:)方法是因為Xcode 9.2(或者Swift 4.1)中的RangeReplaceableCollection協議沒有這個方法!

可是在檢視Section類原始碼時發現,它即使在Xcode 10.0中也沒有實現removeAll(where:)方法,所以我們又可以得出推論:

removeAll(where:)方法是RangeReplaceableCollection協議擴充套件自動為你生成的!你可以免費使用這個方法,只要你遵守RangeReplaceableCollection協議,且在Swift 4.2+中。

更多問題 Come On!!!

至此為止,我們得到了一些線索,有了一些新的認識。但是還有兩個重要問題沒有解決:

1.為什麼免費的removeAll(where:)方法可以做到一次性正確刪除多個Row?它和遍歷刪除到底有什麼不同?
2.我們如何在Swift 4.1中自己實現這個方法?

我們下回分解.