【问题标题】:How do view types like Text or Image conform to the View protocol in SwiftUI?Text 或 Image 等视图类型如何符合 SwiftUI 中的 View 协议?
【发布时间】:2026-02-07 03:20:04
【问题描述】:

SwiftUI 中的视图类型让我很困惑:

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

Text 类型为例。定义如下:

public struct Text : Equatable { ... }

我找不到任何增加符合View 协议的公共扩展,例如

extension Text: View { ... }

official documentation 中的 Relationships 部分简单说明:

符合: 平等

仅此而已。

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

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

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

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

那么这怎么可能呢?

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

【问题讨论】:

    标签: ios swift view swiftui opaque-result-type


    【解决方案1】:

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

    你会发现_UnaryViewView的一个子协议:

    @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 中,Text 通过与 _UnaryView 的一致性间接符合 View。由于_UnaryView 是SDK 的一部分并且以_ 开头,因此Xcode 和Apple 文档隐藏了该符号。所以通过普通的方法是看不到一致性的。

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

    @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
    }
    

    【讨论】:

    • 出色的中肯答案。感谢您解决这个看似矛盾的问题!
    【解决方案2】:

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

    1. 原始视图:TextImageCircle
    2. 容器视图:ListHStackVStack

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

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

    @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
    }
    

    【讨论】:

    • 是的,虽然这可能是真的,但它不能回答指定View 一致性的问题。这是在编译时发生的,而不是在运行时。否则代码将无法编译。
    • 实际上,您在复制的扩展中缺少 View 一致性。扩展文本:视图就是它所说的。它通过扩展符合就是答案。它就在标题中。
    【解决方案3】:

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

    Image 类型具有直接符合View 的扩展:

    extension Image : View {
    }
    

    Circle符合Shape,它本身也符合View

    public struct Circle : Shape {
      ...
    }
    
    public protocol Shape : Equatable, Animatable, View {
      ...
    }
    

    【讨论】:

    • "SwiftUI 视图类型符合 View 协议" → 这是我提出问题的假设。但是在哪里定义了一致性?对于Circle,您可以回答这个问题,但是例如TextHStack 呢?
    【解决方案4】:

    扩展。

       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
    }
    

    【讨论】: