SwiftUI —幫你產出重複畫面的 ForEach

ChunYi LI
One Two Swift
Published in
4 min readJul 14, 2021

在 SwiftUI 的 ForEach 跟 Swift Framework 的 forEach(_:) 是完全不同的兩個東西。

Swift Framework 的 forEach(_:) 是一個根據 Collections 批次處理 Element 的method

SwiftUI 的 ForEach 是一個根據 Range 或是 Data 批次產生 View 的 Structure

Range : 一個不包含上限的範圍。 例: 0..<3 、 4.3..<12.5。

Data : 一個繼承 RandomAccessCollection 這個 protocol 的 Data。

會想要紀錄這個 Structure 是因為在練習 SwiftUI 時注意到 ForEach 的某個建構子。

ForEach(Array(data.enumerated()), id: \.offset) { index, element in    //..}

此時我注意到了一個我以前不曾使用過的東西

\.offest

這個東西到底是表示什麼?為何會在這做使用?

經過一番在官方文件裡翻來覆去,總算理清了頭緒。

ForEach總共有三個建構子

1. init(_ data: Range<Int>, content: @escaping (Int) -> Content) 2. init(_ data: Data, content: @escaping (Data.Element) -> Content)3. init(_ data: Data, id: KeyPath<Data.Element, ID>, content: @escaping (Data.Element) -> Content)

第二跟第三個建構子差別取決於這個繼承 RandomAccessCollection 的 Data 中的 element 有沒有符合 Identifiable 這個 protocol。

由於我練習的專案 data element 並沒有去實作 Identifiable,所以必須在 ForEach initialize 時傳入自定義的 identifier。

根據第三個建構子,我們必須使用 KeyPath 來表示自定義的 identifier。

然而經過 enumerated() 後的 collection 會返回一個 EnumeratedSequence,而這個 EnumeratedSequence 的 element 會是 typealias

我們可以用 keyPath 的表示法 \ + .property

所以在這邊我們可以使用 \.offset 也可以使用 \.element。

以上就是為何 ForEach 的 initializer 為何會有一個 \.offset。

除此之外 ForEach 的使用上都非常友善,你只需要準備好自己的 Collection或 Range,定義好 Content 內部要根據 Collection 產生什麼 View,然後就交給 ForEach 去批次產生 View 就好,此時你只需注意 View 跟 View 之間的間距跟如何排列。

學習 SwiftUI 會有種重新學習 iOS 的感覺,集合了好幾次 WWDC 的內容,如果有一年的 WWDC 沒有認真學習的話,會在學習 SwiftUI 的路上一次撿回來,實在不是件容易的事。

但也因為如此對於Swift 、SwiftUI Framework的官方文件閱讀能力直線上升,根本強迫升級,但對於未來使用 SwiftUI 在產品上也是滿滿的期待。

--

--

ChunYi LI
One Two Swift

Hi this is Chunyi-Li from Taiwan, a junior iOS deveoper