SwiftUIのVStackやHStackでは、下のようにTextを2行並べて書くだけでTextを縦並びにできます。
今回はこの仕組みについて調べてみました。
struct ContentView: View { var body: some View { VStack { Text("AAA") Text("BBB") } } }
上記のコードですが、下のような記述と同等になります。
複数個並べられていたTextは、ViewBuilderのbuildBlockの引数として使われます。
struct ContentView: View { var body: some View { VStack { ViewBuilder.buildBlock( Text("AAA"), Text("BBB") ) } } }
ViewBuilderのbuildBlockは、以下のようなTupleViewを返すメソッドです。
渡されたViewを元にTupleViewを作って返します。
extension ViewBuilder { public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View }
まとめると、省略記法を使わずにVStackを使う場合は以下のような記述になります。
// 元コード // struct ContentView: View { // var body: some View { // VStack { // Text("AAA") // Text("BBB") // } // } // } // 省略せずに書かれたコード struct ContentView: View { var body: some View { VStack(content: { () -> TupleView<(Text, Text)> in return ViewBuilder.buildBlock( Text("AAA"), Text("BBB") ) }) } }
続けて、ViewBuilderを省略できた理由を見ていきます。
省略できたのは、ViewBuilderの宣言についている@_functionBuilderというAttributesが関係しています。
@_functionBuilder public struct ViewBuilder { }
@_functionBuilderを使ってStructを作ると以下の@MyStruct
のようにクロージャーに付けるAttributesが作られます。
func myFunc(@MyStruct closure: () -> Int) -> Int { return closure() } @_functionBuilder struct MyStruct { static func buildBlock(_ v1: Int) -> Int { return v1 } static func buildBlock(_ v1: Int, _ v2: Int) -> Int { return v1 + v2 } static func buildBlock(_ v1: Int, _ v2: Int, _ v3: Int) -> Int { return v1 + v2 + v3 } }
@MyStructを付けたクロージャーは、以下のような省略記法を使えます。
ViewBuilderもこの機能を使う事でViewBuilder.buildBlock
という呼び出しを省略していました。
myFunc { 1 2 } // 上は以下の省略形 myFunc { MyStruct.buildBlock(1, 2) } func myFunc(@MyStruct closure: () -> Int) -> Int { return closure() }
余談ですが@_functionBuilderはclassにも使うことができます。
@_functionBuilder class MyClass { }
以下のように値の数がbuildBlockの引数の数を超えるとエラーになります。
myFunc { 1 2 3 4 }
ViewBuilderは引数が最大10個なので、下のようにViewを11個渡すとエラーになります。
struct ContentView: View { var body: some View { VStack { Text("1") Text("2") Text("3") Text("4") Text("5") Text("6") Text("7") Text("8") Text("9") Text("10") Text("11") } } }
参考URL
SwiftUIの魔法を実現する仕組み (Custom Attributes, Function Builder) - Qiita