在Swift 5.1中,有不透明的类型。我看到例如body
是必需的协议变量。它的合同定义如下:
var body: Self.Body { get }
这意味着我们应该能够将body标记为不可变(没有set
)。必须如何做?不透明变量类型是否可能是不可变的?我尝试过:
import SwiftUI
struct ContentView : View {
init() {
body = AnotherView(body: Text(""))
}
let body: some View
}
struct AnotherView: View {
var body: Text
}
但是我得到一个错误,必须将AnotherView
强制转换为some View
。这样做之后,我得到了错误:
'some'类型仅针对声明的属性类型实现 和下标以及函数的返回类型
我是否能够使用类型为View
的不可变body
变量来遵守some View
(未将其明确标记为AnotherView
)? AnotherView
是some View
,我不明白为什么不能仅将AnotherView
的实例分配给body
。我想保持灵活性,不要在struct之外公开body的实际实现类型,但是我想直接在初始化器中对其进行初始化(因为我要在初始化器中传递值,创建更多属性并在body属性中使用它们是详细)。
答案 0 :(得分:0)
因为没有设置器,所以任何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
协议的东西。