12

关于SwiftUI中的视图类型,有一件大事让我感到困惑:

他们似乎不符合View协议,但不知何故,他们神秘地做到了。

Text类型为例。它的定义如下:

public struct Text : Equatable { ... }

我找不到任何增加View协议一致性的公共扩展,比如

extension Text: View { ... }

官方文档中的“关系”部分简单说明:

符合: 平等

仅此而已,仅此而已。

然而,我可以返回Text一些View需要的实例,例如:

var body: some View {
    Text("I'm a View, I swear!") 
}

如果Text不符合View,这将不可能并引发编译器错误。

(some View是一种不透明的结果类型,这意味着它是具有标识的特定类型,但符合View.)

那么这怎么可能呢?

为SwiftUI视图类型(如、、、 ...)View指定的协议一致性在哪里?TextImageCircle

4

4 回答 4

9

这个问题是在 2019 年 6 月 6 日的 WWDC 期间提出的,当时我们只有 Xcode 11 和 SwiftUI 的第一个测试版。所以正确回答这个问题需要访问该版本的 SwiftUI。您可以在此处下载 Xcode 11 beta 1。(谢谢你,xcodereleases.com!)不过,你正在尝试解压存档,因为(我认为)它是用一个已经过期的证书签名的。我使用了黑魔法(xip在 LLDB 中单步执行命令并在关键时刻修改内存以破坏证书验证)。您或许可以在解包之前将系统时间设置回 2019 年 6 月 6 日。

无论如何,这里是理解为什么Text不符合的秘密View:Xcode 和 Apple 的文档生成器,故意省略 SDK 中以 . 开头的标识符_

因此,如果您想查看一个类型的完整公共声明,您不能依赖 Xcode 或文档来向您展示它。相反,您必须挖掘.swiftinterface模块的文件。对于 SwiftUI,你可以在这里找到它,相对于Xcode.app目录:

Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/SwiftUI.framework/Modules/SwiftUI.swiftmodule/arm64.swiftinterface

在该文件的 Xcode 11 beta 1 版本中,您不会找到直接一致性Text: View. 相反,你会发现:

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension Text : _UnaryView {
  public static func _makeView(view: _GraphValue<Text>, inputs: _ViewInputs) -> _ViewOutputs
  public typealias Body = Swift.Never
}

你会发现这_UnaryView是一个子协议View

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol _UnaryView : SwiftUI.View where Self.Body : SwiftUI._UnaryView {
}

因此,在 Xcode 11 beta 1 和相应的 iOS、macOS、tvOS 和 watchOS beta 中TextView通过其对_UnaryView. 由于_UnaryView是 SDK 的一部分并以 开头_,Xcode 和 Apple 文档隐藏了该符号。所以你不能通过正常的方法看到一致性。

在稍后的某个时间点(但我相信,在 Xcode 11.0 测试版期间),Apple 取消了该_UnaryView协议并Text直接符合View. 因此,如果您检查.swiftinterfaceXcode 11.4(我写这篇文章时的当前版本)中的 SwiftUI 文件,您会发现:

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension Text : SwiftUI.View {
  public static func _makeView(view: SwiftUI._GraphValue<SwiftUI.Text>, inputs: SwiftUI._ViewInputs) -> SwiftUI._ViewOutputs
  public typealias Body = Swift.Never
}
于 2020-04-12T03:04:23.263 回答
1

如您所知,有两种类型是视图..

  1. 原始视图:Text, Image,Circle
  2. 容器视图: List, HStack,VStack

也就是说,下面是 的扩展Text,Body 设置为 Never,这意味着它不允许有一个 body,因为它是一个用于结束 body 循环的原始视图。

因此,(根据我的理解)在运行时 SwiftUIText会在发现原始视图不在容器视图中时包装在容器视图中。

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension Text {

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required `body` property.
    public typealias Body = Never
}
于 2019-06-06T04:22:26.933 回答
0

SwiftUI 视图类型符合View协议,否则正如您提到的代码将无法编译。我发现其中一些在 SwiftUI 公共扩展中可用:

Imagetype 有一个扩展,它直接符合View

extension Image : View {
}

Circle符合Shape,它本身符合View

public struct Circle : Shape {
  ...
}

public protocol Shape : Equatable, Animatable, View {
  ...
}
于 2019-06-06T06:41:02.927 回答
0

扩展名。

   extension Text : View {

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required `body` property.
    public typealias Body = Never
}
于 2020-02-10T09:38:21.047 回答