見出し画像

SwiftUIサンプルの不要なプロトコル

SwiftUI の Disclosure・Outline・List』記事のため、ドキュメントのいくつかのサンプルを試してみました。
公式ドキュメントのサンプルコードはふえる傾向でその点はありがたいのですが、イマイチのものもありました。

List のサンプルを例に、シンプルになるはずのコードを複雑にしている不要なプロトコルの指定について書きます。

サンプルコードは Xcode 13.1 の Playground で実行しました。

サンプル2

Playground で確認するため何行か追加しています。

import SwiftUI
import PlaygroundSupport

struct ContentView: View {
   struct Ocean: Identifiable {
       let name: String
       let id = UUID()
   }
   private var oceans = [
       Ocean(name: "Pacific"),
       Ocean(name: "Atlantic"),
       Ocean(name: "Indian"),
       Ocean(name: "Southern"),
       Ocean(name: "Arctic")
   ]

   var body: some View {
       List(oceans) {
           Text($0.name)
       }
   }
}

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

struct Ocean に注目。
Identifiable プロトコルのみでシンプルですが、List での利用には問題ありません。
let id = UUID() これもシンプルで確実、問題ありません。


Supporting Selection in Lists

次の選択できる List のサンプル

struct Ocean: Identifiable, Hashable {
   let name: String
   let id = UUID()
}
private var oceans = [
   Ocean(name: "Pacific"),
   Ocean(name: "Atlantic"),
   Ocean(name: "Indian"),
   Ocean(name: "Southern"),
   Ocean(name: "Arctic")
]
@State private var multiSelection = Set<UUID>()

var body: some View {
   NavigationView {
       List(oceans, selection: $multiSelection) {
           Text($0.name)
       }
       .navigationTitle("Oceans")
       .toolbar { EditButton() }
   }
   Text("\(multiSelection.count) selections")
}

struct Ocean はなぜか Hashable が追加されています。
Hashable を削除しても動作します。
Hashable は不要です。


Supporting Multi-Dimensional Lists

複数行選択のサンプルも不要なプロトコルが書かれています。

次のコードように struct Sea の Hashable は削除しても動作します。

struct ContentView: View {
   struct Sea: Identifiable {  // Hashable,不要
       let name: String
       let id = UUID()
   }
   struct OceanRegion: Identifiable {
       let name: String
       let seas: [Sea]
       let id = UUID()
   }
   private let oceanRegions: [OceanRegion]  = [
       OceanRegion(name: "Pacific",
                   seas: [Sea(name: "Australasian Mediterranean"),
                          Sea(name: "Philippine"),
                          Sea(name: "Coral"),
                          Sea(name: "South China")]),
       OceanRegion(name: "Atlantic",
                   seas: [Sea(name: "American Mediterranean"),
                          Sea(name: "Sargasso"),
                          Sea(name: "Caribbean")]),
       OceanRegion(name: "Indian",
                   seas: [Sea(name: "Bay of Bengal")]),
       OceanRegion(name: "Southern",
                   seas: [Sea(name:"Weddell")]),
       OceanRegion(name: "Arctic",
                   seas: [Sea(name: "Greenland")])
   ]
   @State private var singleSelection : UUID?

   var body: some View {
       NavigationView {
           List(selection: $singleSelection){
               ForEach(oceanRegions) { region in
                   Section(header: Text("Major \(region.name) Ocean Seas")) {
                       ForEach(region.seas) { sea in
                           Text(sea.name)
                       }
                   }
               }
           }
           .navigationTitle("Oceans and Seas")
           .toolbar { EditButton() }
       }
   }
}


Creating Hierarchical Lists

SwiftUI の Disclosure・Outline・List』記事にも書きましたが、階層表示のサンプルも不要なプロトコル CustomStringConvertible が書かれています。

    struct FileItem: Hashable, Identifiable { // , CustomStringConvertible不要
       var id: Self { self }
       var name: String
       var children: [FileItem]? = nil
       var description: String {
           switch children {
           case nil:
               return "📄 \(name)"
           case .some(let children):
               return children.isEmpty ? "📂 \(name)" : "📁 \(name)"
           }
       }
   }

このままだと var id: Self { self } のために Hashable を削除するとエラーが発生し実行できません。

ほかのサンプルと同じように id = UUID() とすると Hashable も不要です。

struct FileItem: Identifiable { // Hashable, CustomStringConvertible不要
   var id = UUID()  // Self { self } は使わない
   var name: String
   var children: [FileItem]? = nil
   var description: String {
       switch children {
       case nil:
           return "📄 \(name)"
       case .some(let children):
           return children.isEmpty ? "📂 \(name)" : "📁 \(name)"
       }
   }
}

ひとつのページのサンプルで Identifiable の実装がいろいろなのは初学者向けとは言えないと思います。


まとめ

🟠 Apple公式ドキュメントのサンプルは充実してきたがいまいちのものもある

🟠 参考にする場合は自分で確認しよう

🟠 ドキュメントのサンプルを試すには Playground が最適


こちらの記事もぜひご覧ください。

有料記事ですがおよそ半分試読できます。
この記事を含むマガジンもあります。


いいなと思ったら応援しよう!

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