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")
})
)
}
}