寫了一些範例之後,我還是不知道那最基本的 View
protocol 裡面是什麼意思,可能太久沒寫了,這一篇花一點時間搞懂他到底做了什麼事情。
以下內容是 Xcode 11.7, Swift 5 的原始碼。
先看 Protocol 宣告
public protocol View { associatedtype Body : View var body: Self.Body { get }}
一個一個看吧。
如同 generic 的代號
我自己理解的,associatedtype
就是儲存了到時遵守這個協議的類別名稱的類別變數。然後這裡的宣告又清楚指明了該類別必然是遵守 View
協議的。
簡單來說,如果你實作一個 SwiftUI 類別如下:
struct ContentView: View {}
那麼, Body
就代表了 ContentView
這個類別。
類別也有 Self 可用
而首字母大寫的 Self
呢?其實就是相當於物件實例的 self ,所以後面宣告 body
這個 computed property 的內容就告訴你, Body
就是類別級別的 property 了,而他的命名規則也遵守「類別的首字母會大寫」的通用規則,種種跡象告訴你, Body
就是類別。
所以,同上面的案例,其實遵守 View
的類別實作的 body
,應該會是如下:
struct ContentView: View { var body: ContentView { }}
但如果你真的這樣做,你跑起來會遇到一個錯誤:
Cannot convert return expression of type 'some View' to return type 'ContentView'
修復方式是把你實作在 body
裡面的物件轉換成 ContentView
。
不想這麼麻煩,some 關鍵字
先聲明一下,下面的內容其實真的只能當作參考,讀完
opaque type
後我發現要講的太多了,但不想要把這篇寫得更長了。
於是你通常會看到大家不會這樣寫 body
的實作,通常會這樣寫:
struct ContentView: View { var body: some View { }}
所以你可以猜測這個關鍵字的意思了,是的,就像你讀英文小說時,遇到不會的單字就從上下文去猜他的意思, some
應該是代表了他的回傳值是一個類似 View
的東西,不管他到底是什麼,該類別/struct/whatever…遵守 View
協議就對了 (後面讀了一些資料,我發現這樣講並不好,因為聽起來好像是 protocol type,但其實不是,因為他其實是指到一個具體的 type ,只是你不知道是什麼而已,所以這個用法比起光用 protocol ,更加強調了 type 的重要性)。
雖然看起來很像是 protocol 的寫法,但其實這是 opaque type ,簡單說就是把類別的複雜度隱藏在函數實作的邏輯裡面,在這邊也就是說, body
裡面怎樣去結合出畫面的,到底是用了多少 Text
、 ZStack
之類的元件我都不管,我去呼叫 body
的人,只在乎回傳的結果而已。
寫到這裡,我只是想做個結尾,詳情請見 opaque type
,已列在下面可以去看一看喔。