SwiftUIのコードを読み解く
WWDC19参加中です。4日目です。
ラボのSwift Open Hoursにいきまして、SwiftUIのコードを文法レベルで教えてもらいました。
Swift5.1になり、新しい構文がたくさん追加され、SwiftUIはそれをフルに活用しているので
今回はチュートリアルのこちらのコードを読み合わせしました。
struct ContentView: View {
var body: some View {
VStack {
MapView()
.edgesIgnoringSafeArea(.top)
.frame(height: 300)
CircleImage()
.offset(x: 0, y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack(alignment: .top) {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
}
}
}
では一行ずつ読み合わせします。
struct ContentView: View
ContentView
というstructを定義しView
プロトコルに準拠されています。
var body: some View {
VStack{...}
}
body
はコンピューテッドプロパティで型はView
プロトコル。
some
修飾子をつけることでOpaque Result Typeであることを表します。
Opaque Result Typeは内部実装を隠蔽しながらパフォーマンスにも影響しない手段です。
Swift 5.1 に導入される Opaque Result Type とは何か
body
はVStack
のインスタンスを返すコンピューテッドプロパティです。
Swift5.1から単一式の場合にクロージャーだけではなく関数やコンピューテッドプロパティにもreturn
を書かなくても良くなりました。
なので、
var body: some View {
VStack{...}
}
は
var body: some View {
get { //
return VStack{...}
}
}
と同じ意味になります。
VStack{...}
VStack{}
の{}はSwift5.1のFunctionBuilderという機能を利用しています。
SwiftUIの魔法を実現する仕組み (Custom Attributes, Function Builder)
ViewBuilderというアノテーションをつけることでコンパイル時にコードが変換されます。
ViewBuilderの定義はこちら
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@_functionBuilder public struct ViewBuilder {
/// Builds an empty view from an block containing no statements, `{ }`.
public static func buildBlock() -> EmptyView
/// Passes a single view written as a child view (e..g, `{ Text("Hello") }`) through
/// unmodified.
public static func buildBlock<Content>(_ content: Content) -> Content where Content : View
}
今回の例で言えば
VStack {
MapView()
.edgesIgnoringSafeArea(.top)
.frame(height: 300)
CircleImage()
.offset(x: 0, y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack(alignment: .top) {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
}
というソースコードは
VStack {
ViewBuilder.buildBlock(
MapView()
.edgesIgnoringSafeArea(.top)
.frame(height: 300),
CircleImage()
.offset(x: 0, y: -130)
.padding(.bottom, -130),
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack(alignment: .top) {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
)
}
のように変換されるとのことです。
疑問点
VStackでViewBuilderがなぜ使えるのかがわからない。
明日Labで疑問解消します。