SwiftiUI 提供了一個結構體 AnyView
來表示任意一個 View 實例,和 Any
一樣可以用來抹除具體的類型。
假設我們有一個頁面展示用戶的信息,如果沒有用戶沒有登錄我們就展示一個登錄按鈕。根據狀態不同,一個 View 可能會返回不同實例類型的 View:
struct UserInfoView: View {
@State var isLogin = false
var body: some View {
if isLogin {
return Text("Logined”)
} else {
return Button(action: {
// 去登錄
}, label: {
return Text("Login")
})
}
}
}
那么上面的代碼能不能被編譯通過呢?
直覺上我們認為返回的只要是實現了 View 協議的都能滿足,應該能編譯通過。不過實際上這樣寫會編譯器會提供一個錯誤:
Function declares an opaque return type, but the return statements in its body do not have matching underlying types
問題就出在前面的關鍵字 some
上。加了 some
后協議透明,編譯器在編譯時推斷具體代碼的實際返回類型,因此要求必須只能有一個確定的類型。具體關于 some
我在之前的博客 Swift 5.1 新特性:透明類型關鍵字 some 有介紹過。
上面的例子中用戶已登錄時返回 Text,沒登錄返回 Button 類型。不是同一種類型,編譯器因此拋出錯誤。為了解決這個問題我們很自然想到用一個通用的類型把所有的 View 都包起來,這樣編譯器可以編譯通過。反正運行的時候是 View 就可以了。這就是 AnyView
的使用場景了,抹掉具體 View 類型,對外有一個統一的類型,上面的代碼這樣改一下就可以了:
var body: some View {
if isLogin {
return AnyView(
Text("User logined")
)
} else {
return AnyView(
Button(action: {
// 去登錄
}, label: {
return Text("Login")
})
)
}
}