SwiftUIだとローカル変数の定義でエラーになることが多いので整理してみました。
SwiftUIでのローカル変数定義方法
bodyの中の場合は下のようにreturnを付けることで定義できます。
struct ContentView: View { var body: some View { let a = 1 return Text("Hello, World!") } }
ZStackのように複数Viewを返す場合はreturnを付けた上で() -> TupleView<(Text, Text)>
のように戻り値の型を指定する必要があります。
struct ContentView: View { var body: some View { ZStack { () -> TupleView<(Text, Text)> in let a = 1 return ViewBuilder.buildBlock( Text("AAA"), Text("BBB") ) } } }
定義に関する調査
なぜ上記方法でうまくいくかの調査は下の通りです。
下のように変数を定義するとFunction declares an opaque return type, but has no return statements in its body from which to infer an underlying type
というエラーになります。
これは値をreturnしていないというエラーです。
struct ContentView: View { var body: some View { let a = 1 Text("Hello, World!") } }
以下のようにreturnを付けることでエラーは出なくなります。
struct ContentView: View { var body: some View { let a = 1 return Text("Hello, World!") } }
ローカル変数を定義するまで動いていたのはSwiftのreturn文省略の仕様が理由です。
Swiftはクロージャー内が1行だけの場合はreturnを省略できるので、変数定義をしなければreturnを省略することができます。
struct ContentView: View { var body: some View { Text("Hello, World!") } }
mapメソッドなどでもreturnが不要なのはこの仕様が理由になります。
[1, 2, 3].map { $0 * 2 }
メソッドも同じようにreturnを省略できます。
struct ContentView: View { func test() -> some View { Text("Hello, World!") } }
returnを付ける方法ですが、Zstackの中では使うことができません。
下のように書くとCannot convert return expression of type 'ZStack<_>' to return type 'some View'
というエラーになります。
これはZStack<_>をsome Viewに変換できないというエラーです。
struct ContentView: View { var body: some View { ZStack { let a = 1 return Text("Hello, World!") } } }
このエラーは下のようにZStackの戻り値の型を宣言することで解消できます。
struct ContentView: View { var body: some View { ZStack { () -> Text in let a = 1 return Text("AAA") } } }
複数Viewを返す場合は下のようにViewBuilderを使ってTupleViewを作る必要があります。
struct ContentView: View { var body: some View { ZStack { () -> TupleView<(Text, Text)> in let a = 1 return ViewBuilder.buildBlock( Text("AAA"), Text("BBB") ) } } }