问题描述
据我所知,ViewModifier协议的定义如下:
protocol ViewModifier {
// content view type passed to body()
typealias Content
// type of view returned by body()
associatedtype Body : View
// only requirement
func body(content: Self.Content) -> Self.Body
}
我的问题是:
为什么Self.Content
是typealias
而Self.Body
是associatedtype
?
有什么区别?
解决方法
为什么
Self.Content
是typealias
而Self.Body
是associatedtype
?有什么区别?
由于Content
是typealias
,因此ViewModifier
协议的作者在编写协议时会选择别名的类型。 (您看不到别名的类型,因为该类型是_ViewModifier_Content<Self>
。当SDK中的标识符以_
开头时,Apple会从文档和生成的接口中忽略该标识符。)
由于Body
是associatedtype
,因此您在编写符合ViewModifier
协议的类型时可以选择别名。您可以将Body
设置为任意类型,但要满足两个条件:
-
您必须选择符合
View
的类型(因为ViewModifier
协议约束Body
符合View
)。 -
您必须能够创建或获取您选择的任何类型的实例,因为您必须从
body
方法返回它的实例。 (或者您可能会崩溃或挂起以避免完全返回,但这通常不是您想要的……)
因此,当您实现符合ViewModifier
的类型时,就无法影响Content
的含义。它始终表示_ViewModifier_Content<Self>
。但是您可以通过选择Body
方法的返回类型来选择body
的含义。
在这里,我将强制Body
表示EmptyView
:
struct EmptyModifier: ViewModifier {
func body(content: Content) -> EmptyView {
EmptyView()
}
}
在这里,我将强制Body
表示Color
:
struct RedModifier: ViewModifier {
func body(content: Content) -> Color {
Color.red
}
}
通常,我们使用some View
作为类型,这意味着Swift会为我们推断出确切的类型并将其保密:
struct FrameModifier: ViewModifier {
var color: Color
var width: CGFloat
func body(content: Content) -> some View {
return content
.padding(width)
.border(color,width: width)
}
}
在这里,我们对Body
类型的了解仅在于它符合View
。 Swift尽力阻止我们在编译时发现真实类型。
-
typealias
仅更改类型的名称。没什么。 -
associatedtype
是在协议实现中包含泛型的一种方式。
public protocol ViewModifier {
/// The type of view representing the body of `Self`.
associatedtype Body : View
/// Returns the current body of `self`. `content` is a proxy for
/// the view that will have the modifier represented by `Self`
/// applied to it.
func body(content: Self.Content) -> Self.Body
/// The content view type passed to `body()`.
typealias Content
}
在上面的示例中,Body
是符合View
的具体类型,并由body(content:)
返回类型来推断。
Content
只是作为content
参数传递的类型的另一个名称。
rob mayoff的
This answer更详细地解释了ViewModifier
:
因此,这告诉我们,当我们编写自己的
ViewModifier
时,我们的body
方法将收到某种View
(具体类型由 框架,我们可以将其命名为Content
),然后返回某种形式 的View
(我们将选择特定的返回类型)。
这意味着您不知道Content
是什么,您只需对其进行操作-为方便起见,它被称为Content
,因此您不必处理_ViewModifier_Content<Self>