Text 或 Image 等视图类型如何符合 SwiftUI 中的 View 协议?
Posted
技术标签:
【中文标题】Text 或 Image 等视图类型如何符合 SwiftUI 中的 View 协议?【英文标题】:How do view types like Text or Image conform to the View protocol in SwiftUI? 【发布时间】:2019-06-06 03:40:26 【问题描述】: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 视图类型(如 Text
、Image
、Circle
、...)指定的 View
协议一致性在哪里?
【问题讨论】:
【参考方案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
你会发现_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 中,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】:如您所知,视图有两种类型..
-
原始视图:
Text
、Image
、Circle
等
容器视图:List
、HStack
、VStack
等
也就是说,下面是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
,您可以回答这个问题,但是例如Text
或HStack
呢?【参考方案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
【讨论】:
以上是关于Text 或 Image 等视图类型如何符合 SwiftUI 中的 View 协议?的主要内容,如果未能解决你的问题,请参考以下文章
如何解决 不能以 DISTINCT 方式选择 textntext 或 image 数据类型
delphi程序中使用union all 查询sql数据中的两个表报"不能比较或排序 text、ntext和image类型"的错误。
“类型‘()’不能符合‘视图’;只有结构/枚举/类类型可以符合协议”