每个原始视图都有一个body
,但它在编译时不能直接访问。官方 Swift 论坛有关于这个主题的话题。我将在这里重现我的分析。
让我们考虑一下Text
.
A Text
值有一个body
财产,正如所有View
s do. Text
's body
calls fatalError
:
import SwiftUI
func body<V: View>(of view: V) -> V.Body { view.body }
body(of: Text("hello"))
// runtime output:
SwiftUI/View.swift:94: Fatal error: body() should not be called on Text.
但是,如果我们尝试访问body
直接使用属性,编译器会拒绝该程序:
import SwiftUI
Text("hello").body
Output:
![Xcode showing an error message attached to the use of ‘body’. The error message says “Value of type 'Text' has no member 'body'”.](https://i.stack.imgur.com/1FmxO.png)
编译器拒绝该程序,因为 SwiftUI 的swiftinterface
文件没有声明 body 属性Text
.
为什么不Text
的声明包括body
?我不确定,因为我无法访问 SwiftUI 源代码,但我发现我们可以使用@_spi省略声明.swiftinterface
file.
我将以下内容放入MyView.swift
:
import SwiftUI
public struct MyView: View {
@_spi(Private)
public var body: Never { fatalError() }
}
然后我根据找到的“直接调用编译器”指令进行如下编译here:
swiftc MyView.swift -module-name MyLib -emit-module -emit-library -emit-module-interface -enable-library-evolution
编译器这样写MyLib.swiftinterface
如下,省略body
宣言:
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.7 (swiftlang-5.7.0.123.7 clang-1400.0.29.50)
// swift-module-flags: -target arm64-apple-macosx12.0 -enable-objc-interop -enable-library-evolution -module-name MyLib
import Swift
import SwiftUI
import _Concurrency
import _StringProcessing
public struct MyView : SwiftUI.View {
public typealias Body = Swift.Never
}
它写道MyLib.private.swiftinterface
如下,包含body
宣言:
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.7 (swiftlang-5.7.0.123.7 clang-1400.0.29.50)
// swift-module-flags: -target arm64-apple-macosx12.0 -enable-objc-interop -enable-library-evolution -module-name MyLib
import Swift
import SwiftUI
import _Concurrency
import _StringProcessing
public struct MyView : SwiftUI.View {
@_spi(Private) @_Concurrency.MainActor(unsafe) public var body: Swift.Never {
get
}
public typealias Body = Swift.Never
}
所以我最好的猜测是 SwiftUI 应用了@_spi
归因于body
每个原语的属性View
.