SwiftUI中的内容是什么?

SwiftUI中的内容是什么?,swift,swiftui,Swift,Swiftui,在文档中,我在不同的上下文中看到内容: /// A modifier that can be applied to a view or other view modifier, /// producing a different version of the original value. @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) public protocol ViewModifier { /// The co

在文档中,我在不同的上下文中看到
内容

/// A modifier that can be applied to a view or other view modifier,
/// producing a different version of the original value.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol ViewModifier {
    /// The content view type passed to `body()`.
    typealias Content
}
这里呢

/// A view that arranges its children in a vertical line.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public struct VStack<Content> where Content : View {
///在垂直线上排列其子视图的视图。
@可用(iOS 13.0、OSX 10.15、tvOS 13.0、watchOS 6.0、*)
公共结构VStack,其中内容:查看{

我在文档中找不到对
内容
含义的正确解释。SwiftUI中是否有任何预定义的
内容
用法?

了解SwiftUI大量使用泛型类型非常重要。在SwiftUI(和Combine)发布之前,我从未见过任何Swift代码如此大量地使用泛型。SwiftUI中几乎所有的
视图
-一致类型(和
视图修改器
-一致类型)都是泛型类型

ViewModifier
因此,首先让我们讨论一下
ViewModifier
ViewModifier
是一个协议。其他类型可以符合
ViewModifier
,但没有变量或值可以只具有普通类型
ViewModifier

为了使类型符合
ViewModifier
,我们定义了一个
body
方法,该方法接受
内容(不管是什么),并返回
body
(不管是什么):

ViewModifier
本质上就是这一种方法,它将
内容
作为输入,并返回
主体
作为输出

什么是
Body
ViewModifier
将其定义为带有约束的
关联类型

associatedtype Body : View
这意味着我们可以在
ViewModifier
中选择称为
Body
的特定类型,并且我们可以为
Body
选择任何类型,只要它符合
视图
协议

任何
内容
?文档告诉您它是
类型别名
,这意味着我们可能无法选择它是什么。但是文档没有告诉您
内容
是什么的别名,所以我们不知道
正文
可以对它接收的
内容
做什么

文档没有告诉您的原因是Xcode被编程为不显示SDK中的公共符号,如果该符号以下划线(
\uuu
)开头但是,通过查看SwiftUI的
.swiftinterface
文件,您可以看到
ViewModifier
的真实定义,包括隐藏的符号。我解释了如何在中查找该文件

查阅该文件,我们找到了
ViewModifier
的真正定义:

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol ViewModifier {
  static func _makeView(modifier: SwiftUI._GraphValue<Self>, inputs: SwiftUI._ViewInputs, body: @escaping (SwiftUI._Graph, SwiftUI._ViewInputs) -> SwiftUI._ViewOutputs) -> SwiftUI._ViewOutputs
  static func _makeViewList(modifier: SwiftUI._GraphValue<Self>, inputs: SwiftUI._ViewListInputs, body: @escaping (SwiftUI._Graph, SwiftUI._ViewListInputs) -> SwiftUI._ViewListOutputs) -> SwiftUI._ViewListOutputs
  associatedtype Body : SwiftUI.View
  func body(content: Self.Content) -> Self.Body
  typealias Content = SwiftUI._ViewModifier_Content<Self>
}
请注意,我们不必命名
body
返回的
视图的类型。我们可以使用
一些视图
,让Swift推断特定类型

我们可以这样使用它:

Text("Hello").modifier(MyModifier(color: .red))
VStack
现在我们来谈谈
VStack
VStack
类型是一个
struct
,而不是一个协议。它是泛型的,这意味着它需要类型参数(就像函数需要函数参数一样).
VStack
采用一个名为
Content
的类型参数。这意味着
VStack
定义了一个类型族,它允许
内容的每种类型都有一个

由于
VStack
内容
参数被约束为符合
视图
,这意味着对于每个符合
视图
的类型,都有相应的
VStack
类型。对于
文本
(符合
视图
),有
VStack
。对于
图像
,有
VStack
。对于
颜色
,有
VStack

但是我们通常不会详细说明我们正在使用的
VStack
的完整类型实例,而且我们通常不会让
内容
类型像
文本
图像
那样是一个基本类型。使用
VStack
的全部原因是在一列中排列多个视图。
VStack
的使用告诉Swift去arra垂直调整其子视图,并且
VStack
Content
type参数指定子视图的类型

例如,当您编写以下内容时:

VStack {
    Text("Hello")
    Button(action: {}) {
        Text("Tap Me!")
    }
}
您实际上正在创建此类型的实例:

VStack<TupleView<(Text, Button<Text>)>>
VStack
这里的
Content
type参数是type
TupleView
,它本身是一个泛型类型
TupleView
,它自己的类型参数名为
T
,而
T
这里是
(文本,按钮)
(一个2元组,也称为一对)因此类型的
VStack
部分告诉SwiftUI垂直排列子视图,
TupleView
部分告诉SwiftUI有两个子视图:一个
Text
和一个
按钮


您可以看到,即使是这个简短的示例,也是如何生成一个具有多个嵌套泛型参数级别的类型的。因此,我们肯定希望让编译器为我们找出这些类型。这就是为什么苹果在Swift中添加了
some View
语法,以便让编译器找出确切的类型。

这也可能有帮助:

private struct FormItem<Content:View>: View {
    var label: String
    let viewBuilder: () -> Content
    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(label).font(.headline)
            viewBuilder()
        }
    }
}
因为
viewBinder
struct
的最后一个属性,所以您可以将内容放在
FormItem
函数调用之后。

我喜欢,当我发现这个问题时,这回答了我的隐式问题,但我想我可以扩展Kontiki的评论,适用于不熟悉Swift或泛型的程序员


这个问题问了几个问题,特别是:

SwiftUI中的内容是什么

令人惊讶的是,在SwiftUI中没有实际的
内容
类或结构或类型
(据我所知)!问题中的两个示例都提供了这方面的证据

我是什么意思?
Content
是一个,有点像“保存类型的变量”(尽管我觉得这个解释令人困惑)

泛型真的很酷(这就是为什么Swift&XCode autocomplete知道你把字符串放在
VStack<TupleView<(Text, Button<Text>)>>
private struct FormItem<Content:View>: View {
    var label: String
    let viewBuilder: () -> Content
    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(label).font(.headline)
            viewBuilder()
        }
    }
}
FormItem(label: "Your Name") {
    TextField("name", text: $bindingToName)
}
VStack { // Function starts at `{`
    Text("test")
    Text("test 2")
} // Function ends at `}`