Reputation: 17241
There is one big thing that confuses me about view types in SwiftUI:
They don't seem to conform to the View
protocol, but somehow, they mysteriously do.
Take the Text
type for example. It's defined as follows:
public struct Text : Equatable { ... }
I can't find any public extension that adds conformance to the View
protocol, like
extension Text: View { ... }
and the Relationships section in the official documentation simply states:
Conforms To: Equatable
Nothing more, that's all.
Yet, I can return an instance of Text
where some View
is required, for example:
var body: some View {
Text("I'm a View, I swear!")
}
If Text
didn't conform to View
, this wouldn't be possible and throw a compiler error.
(some View
is an opaque result type which means it's a specific type with an identity, but one that conforms to View
.)
So how is this possible?
View
protocol conformance specified for SwiftUI view types (like Text
, Image
, Circle
, ...)?Upvotes: 16
Views: 4991
Reputation: 19642
The extension conforms to View
:
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
}
Upvotes: 0
Reputation: 385690
This question was asked on June 6, 2019, during WWDC, when we only had the first beta of Xcode 11 and SwiftUI. So answering this question correctly requires access to that version of SwiftUI. You can download Xcode 11 beta 1 here. (Thank you, xcodereleases.com!) You are in for an adventure trying to unpack the archive, though, because (I think) it was signed with a certificate that has since expired. I resorted to black magic (stepping through the xip
command in LLDB and modifying memory at a key moment to subvert the certificate verification). You could perhaps just set your system time back to June 6, 2019 before unpacking.
Anyway, here's the secret to understanding why Text
didn't appear to conform to View
: Xcode, and Apple's documentation generator, intentionally omit identifiers in the SDK that start with _
.
So if you want to see the full public declaration of a type, you cannot rely on Xcode or the documentation to show it to you. Instead, you have to dig up the .swiftinterface
file for the module. For SwiftUI, you can find it here, relative to the Xcode.app
directory:
Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/SwiftUI.framework/Modules/SwiftUI.swiftmodule/arm64.swiftinterface
In the Xcode 11 beta 1 version of that file, you won't find a direct conformance Text: View
. Instead, you will find this:
@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
}
And you will find that _UnaryView
is a sub-protocol of View
:
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol _UnaryView : SwiftUI.View where Self.Body : SwiftUI._UnaryView {
}
So, in Xcode 11 beta 1 and the corresponding iOS, macOS, tvOS, and watchOS betas, Text
conforms to View
indirectly, through its conformance to _UnaryView
. Since _UnaryView
is part of the SDK and begins with _
, Xcode and the Apple documentation hide that symbol. So you can't see the conformance through normal methods.
At some later point (but still, I believe, during the Xcode 11.0 beta period), Apple eliminated the _UnaryView
protocol and made Text
conform directly to View
. So if you check the SwiftUI .swiftinterface
file in Xcode 11.4 (the current version as I write this), you'll find this:
@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
}
Upvotes: 14
Reputation: 1669
As you know there are 2 types are Views..
Text
, Image
, Circle
etc List
, HStack
, VStack
etcThat said, below is an extension for Text
, Body is set to Never which means its not allowed to have a body because it is a primitive view that is meant for ending body cycle.
So,(per my understanding) at runtime SwiftUI wraps Text
inside a container view when it finds a primitive view not being inside a container view.
@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
}
Upvotes: 1
Reputation: 19708
SwiftUI view types ARE conforming to the View
protocol, otherwise as you mentioned the code wouldn't compile. I found some of these which were available in SwiftUI public extensions:
Image
type has an extension which directly conforms to View
:
extension Image : View {
}
Circle
conforms to Shape
, which itself conforms to View
:
public struct Circle : Shape {
...
}
public protocol Shape : Equatable, Animatable, View {
...
}
Upvotes: 0