不可变的某些视图主体变量/视图中的不透明返回

时间:2019-06-05 21:52:32

标签: swift swiftui

在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)? AnotherViewsome View,我不明白为什么不能仅将AnotherView的实例分配给body。我想保持灵活性,不要在struct之外公开body的实际实现类型,但是我想直接在初始化器中对其进行初始化(因为我要在初始化器中传递值,创建更多属性并在body属性中使用它们是详细)。

1 个答案:

答案 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协议的东西。