見出し画像

SwiftUIのbodyが少し変わっていた

SwiftUI の Disclosure・Outline・List』記事用に DisclosureGroup のサンプルを作っていたとき、レイアウトを上によせたくて Spacer() を追加しました。
こんな感じ:

    var body: some View {
       DisclosureGroup(isExpanded: $topExpanded) {
           Toggle("Toggle 1", isOn: $toggleStates.oneIsOn)
           Toggle("Toggle 2", isOn: $toggleStates.twoIsOn)
           DisclosureGroup {
               Text("オプション 1")
               Text("オプション 2")
           } label: {
               Label("オプション", systemImage: "gearshape.2")
           }
       } label: {
           Label("設定", systemImage: "gearshape")
       }
       Spacer()   // 👈
   }

これで DisclosureGroup は上辺にぴったり接して表示されました。

でも、違和感が...

body は計算型プロパティーなので一つのViewしか返すことができないはず

このような場合は VStack が必要だったはずだ。(またはGroupや@ViewBuilder)
コンテナビューを使わずに二つのビューを記述できて、表示もできている。
ナゼ?


Xcode 13 が特別なのか? SwiftUIの機能強化か?

現在使っているのは Xcode 13 です。
SwiftUI の bodyのドキュメントを見ても理由がわかりません。
SwiftUI の機能追加ではないのか?
Playground アプリ(バージョン3.4.1)でも問題なく実行できます。

サンプルは iPad の Playground アプリでも実行して確認している。
正常に表示されていたので、気付くのが遅れました。


確認用に、次のサンプルコードを作り調べてみました。

import SwiftUI
import PlaygroundSupport

struct BodySample: View {

   var body: some View {
       Text("オプション 1")
       Text("オプション 2")
       Text("オプション 3")
       Text("オプション 4")
       Text("オプション 5")
       Text("オプション 6")
       Text("オプション 7")
       Text("オプション 8")
       Text("オプション 9")
       Text("オプション 10")
//        Text("オプション 11")

   }
}

// playgroundで実行する場合に必要なコード
PlaygroundPage.current.setLiveView(
   BodySample()
      .frame(width: 300, height: 500) // XcodeのPlaygroundで必要
)


Xcode 11 ではエラー

このコードを Xcode 11.3.1Xcode 11.7 で試したところ、予想どおりのエラーが表示されました。

画像1

シンプルにするため、まず二つのTextで試しました。

もちろん、一つだけの Text なら問題なく表示できます。


Xcode 12.3 では正常に実行できる!

Xcode 12.3 では実行できました。
二つの Text も10個でも表示でき、11個ではエラーとなるので ViewBuilder と予想されます。

Xcode 12 は2020年秋のリリースだから、WWDC 2020のセッションを調べてみました。

SwiftUIの新機能』(日本語字幕あり)では見つけられません。
(字幕テキストを body で検索してみました)

Swiftの新機能』(日本語字幕あり)で説明がありました。
(下記リンクはこの件を説明している部分から再生します)

ビデオでは Scene の説明の部分で触れていた。

スクリーンショット 2021-10-14 15.52.32


スクリーンショット 2021-10-14 15.53.03

確かに WindowGroup と Settings が計算型プロパティで @SceneBuilder 属性なしに記述できている。

『プロトコル要件からの推論』されるとのこと。


つまり

   @ViewBuilder var body: some View {
       Text("オプション 1")
       Text("オプション 2")
   }

のように ViewBuilder 属性付きと推論されるので複数(10個まで)ビューを記述できるとのこと。

あ〜スッキリした。
やはり疑問点は早めに解消するのが吉ですね。

推論は Swift の特徴で強力ですが、いざ調べようとするとキーワードがないだけにやっかいですね。
今回も Xcode のリリースノートや SwiftUI のドキュメントを見ても解決せず、古いXcodeで確認しながら調べなければなりませんでした。


🟢 SwiftUI のビューの body で複数のビューを記述できるようになっていた。

🟢 Swift 5.3 からの機能なので Xcode 12 や Playgroundアプリでも問題なし。


きっかけとなった記事「SwiftUI の Disclosure・Outline・List」も公開しました。
有料記事ですがおよそ半分試読できます。

この記事はマガジン『iOSアプリ開発2021』でも読めます。
マガジンは記事2本文の価格でお得に複数の記事が読めます。


ここから先は

0字
最新有料記事をまとめて、リーズナブルに読めます。

iOSアプリ開発関連有料記事をまとめて読めます。

今後も記事を増やすつもりです。 サポートしていただけると大変はげみになります。