【问题标题】:Why does `ViewModifier` protocol has an `associatedtype` AND a `typealias`?为什么“ViewModifier”协议有一个“关联类型”和一个“类型别名”?
【发布时间】:2020-09-10 12:19:32
【问题描述】:

据我所知,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.ContenttypealiasSelf.Bodyassociatedtype ? 有什么区别?

【问题讨论】:

  • Body 将被推断 从您的返回,因此它是关联类型,Content 将提供 给您,ViewModifer 知道(因为由它生成),但为你隐藏,typealias 也是如此。

标签: swiftui swift-protocols type-alias associated-types


【解决方案1】:

为什么 Self.ContenttypealiasSelf.Bodyassociatedtype ?有什么区别?

因为Contenttypealias,所以ViewModifier 协议的作者在编写协议时可以选择别名类型。 (您看不到别名的类型,因为该类型是 _ViewModifier_Content<Self>。当 SDK 中的标识符以 _ 开头时,Apple 会在文档和生成的接口中省略该标识符。)

因为Bodyassociatedtype,当您编写符合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的定义。然后,每个一致性都以自己的方式完全定义associatedtype。这是typealiasassociatedtype 之间的区别。我的EmptyModifierRedModifierFrameModifier 示例是三种不同的一致性。每个一致性对Body 的定义不同。如果Bodytypealias,它将完全由ViewModifier 定义,而我的三个一致性不能给它三个不同的定义。
【解决方案2】:
  • 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 参数传递的类型的另一个名称。


This answer by rob mayoff 更详细地解释了ViewModifier

所以这告诉我们,当我们编写自己的 ViewModifier 时,我们的 body 方法将收到某种View(具体类型由 框架,我们可以称它为Content),并返回某种 的View(我们可以选择具体的返回类型)。

这意味着你不知道Content是什么,你只是对其进行操作——为了方便起见,它被称为Content,所以你不必处理_ViewModifier_Content<Self>

【讨论】:

  • associatedtype 是一种在协议实现中包含泛型的方法 它只是一种包含另一个类型类/协议的方法。例如您也可以使用不是协议的@​​987654339@...
猜你喜欢
  • 2019-09-01
  • 1970-01-01
  • 2020-11-14
  • 2022-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多