在 Swift 5.1 中,有不透明类型。我看到例如body
是必需的协议变量。它的合约定义如下:
var body: Self.Body { get }
这意味着我们应该能够将身体标记为不可变(没有set
)。必须如何做到这一点?不透明变量类型是否有可能不可变?我试过了:
import SwiftUI
struct ContentView : View {
init() {
body = AnotherView(body: Text(""))
}
let body: some View
}
struct AnotherView: View {
var body: Text
}
但是我得到一个错误,AnotherView
必须投射到some View
.这样做之后,我收到错误:
"某些"类型仅针对声明的属性类型实现 以及函数的下标和返回类型
我是否能够符合View
类型为some View
的不可变body
变量(不将其显式标记为AnotherView
)?AnotherView
some View
,我不明白为什么不能将AnotherView
的实例分配给body
。我想保持灵活性,不要在结构体外部公开主体的实际实现类型,但我想直接在初始值设定项中初始化它(因为我在初始值设定项中传入值,创建更多属性并在 body 属性中使用它们是冗长的)。
因为没有资源库,所以任何作为值类型的body
实现都是不可变的。var
只是意味着body
是延迟评估的,而不是它是可变的。你可以声明let body
,但是,正如你所指出的,这暴露了底层View
的实现:
public struct StaticTextView : View {
public let body: Text
public init(string: String) {
self.body = Text(string)
}
}
解决此问题的一种方法是body
只返回一个内部私有值,如下所示:
public struct StaticTextView : View {
private let textView: Text
public var body: some View { textView }
public init(string: String) {
self.textView = Text(string)
}
}
但是,您应该记住,body
设计为在任何绑定状态更改时动态运行,如果要将视图分配给常量,则该视图层次结构中的任何内容都不能绑定到任何动态状态。例如,这是不可能的:
struct DynamicStepperView : View {
@State var stepperValue = 1
var body: some View {
Stepper(value: $stepperValue, in: 1...11, label: { Text("Current Value: (stepperValue)") })
}
}
如果您的主要关注点是防止视图层次结构的实现详细信息泄露,请注意,some View
的不透明返回类型对代码的任何客户端都是不透明的,除了它是符合View
协议的某些东西之外,它们将无法看到底层实现的任何详细信息。