SwiftUI - リストとページとJSON

1. はじめに

リストはListの使い方についてという記事にまとめたので、ここでは、JSONデータでリストと詳細ページを出力する方法をまとめておこうと思います。リストと詳細ページはコンポーネント化もしているのではじめに作成するファイルと役割を整理しておこうと思います。

  • RowView.swift - リストの1行を設定するファイル
  • DetailView.swift - 詳細ページを設定するファイル
  • ModelData.swift - JSONファイルを変換するためのファイル(SwiftUIチュートリアルのコードを使用しています)
  • DataType.swift - JSONファイルの型を設定するファイル
  • ContentData.json - 出力する内容を書くJSONファイル
  • ContentView.swift - リストと詳細ページをまとめて出力するファイル(SwiftUIのプロジェクト開始時に作成される)

2. JSONデータと変換

まずは、ContentData.jsonというファイルを作成して下記を記述してプロジェクトに追加しておきます。メニューの「File > Add Files to ...」から追加できます。

[
  {
    "id": 1,
    "title": "title1",
    "content": "content1"
  },
  {
    "id": 2,
    "title": "title2",
    "content": "content2"
  },
  {
    "id": 3,
    "title": "title3",
    "content": "content3"
  }
]

次にDataType.swiftというファイルを作成しJSONファイルの内容にあわせて型を定義します。

import Foundation

struct DataType: Codable {
  var id: Int
  var title: String
  var content: String
}

Codable - JSON などの外部表現をエンコード、デコードできる型

ModelData.swiftというファイルを作成し下記を記述します。このファイルでJSONデータの読み込みと変換をします。このコードはSwiftUIチュートリアルのstep10にあります。

import Foundation

var allData: [DataType] = load("ContentData.json")

func load<T: Decodable>(_ filename: String) -> T {
  let data: Data

  guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
  else {
    fatalError("Couldn't find \(filename) in main bundle.")
  }

  do {
    data = try Data(contentsOf: file)
  } catch {
    fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
  }

  do {
    let decoder = JSONDecoder()
    return try decoder.decode(T.self, from: data)
  } catch {
    fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
  }
}

guard let 条件 else {...} - nilのチェックをしてアンラップ
Bundle.main.url(forResource: ファイル名, withExtension: 拡張子) - プロジェクト内のファイル名までのURLを取得
Data(contentsOf: url) - データオブジェクトの初期化
JSONDecoder() - JSONオブジェクトからデータ型のインスタンスをデコード

3. 各コンポーネントを作成

RowView.swiftファイルを作成します。このファイルでリストの1行に表示させるものを設定します。

import SwiftUI

struct RowView: View {
  var data: DataType
  var body: some View {
    Text(data.title)
  }
}

struct RowView_Previews: PreviewProvider {
  static var previews: some View {
    RowView(data: allData[0])
  }
}

DetailView.swiftファイルを作成します。このファイルで詳細ページに表示させるものを設定します。

import SwiftUI

struct DetailView: View {
  var data: DataType
  var body: some View {
    VStack {
      Text(data.content)
    }
    .navigationTitle(Text(verbatim: data.title))
    .navigationBarTitleDisplayMode(.inline)
  }
}

struct DetailView_Previews: PreviewProvider {
  static var previews: some View {
    DetailView(data: allData[0])
  }
}

4. まとめて出力

alt

ContentView.swiftに上記で作成したものを出力する設定を記述します。これでGif画像のようなものが出力させると思います。

import SwiftUI

struct ContentView: View {
  var body: some View {
    NavigationView {
      List(allData, id: \.id) { item in
        NavigationLink(destination: DetailView(data: item)) {
          RowView(data: item)
        }
      }
      .navigationTitle("List")
    }
  }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

NavigationLink(destination: リンク先) - ナビゲーションリンクを作成

続きの記事>> リストとお気に入りとフィルター

JSONDecoder | Apple Developer Documentation