[SwiftUI] Environment 変数を作る方法

SwiftUI

@Environment から様々なシステム情報を取得できますが、@Environment 経由で自分で定義したキー値を使って、値を共有することもできます。その方法を説明します。

@Environment

既に定義されている Environment

CoreData を使う時の \.managedObjectContext や
シート等を閉じる時の \.presentationMode 等が有名かと思いますが、非常に多くの情報が定義されています。

Apple のドキュメントは、こちら

斜め読みだけでもしてみると、面白い発見があるかと思います。

Environment 変数の使い方

CoreData を使うコードでは、Environment 経由で ManagedObjectContext を参照します。

変数定義の時に、以下のように @Environment を指定して定義します。

Environment 使用例

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext
...

Environment 変数は、アクセス前に事前にどこかで設定されていなければいけません。多くのシステム定義の変数は、システム側で設定してくれていますが、全てではありません。

設定が必要となる時は、上位のビューで設定して、下位のビューから参照します。上位のビューでは、以下のように .environment を使って設定します。

Environment 設定例

@main
struct CoreDataAppApp: App {
    let persistenceController = PersistenceController.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

# 上記は、Xcode が生成するテンプレートから引用しています。

自分の Environment を作る

キー値の定義

EnvironmentKey という protocol に準拠する形で定義します。

Environment のキー定義

struct MyEnvironmentKey: EnvironmentKey {
  typealias Value = String
  
  static var defaultValue: String = "Default String"
}

参照場所、保存場所を定義

実際に、Environment でアクセスされる場所として EnvironmentValues がありますので、それを拡張するように プロパティとアクセサを定義します。

EnvironmentValues の extension 例

extension EnvironmentValues {
  var myEnvironment: String {
    get {
      return self[MyEnvironmentKey.self]
    }
    set {
      self[MyEnvironmentKey.self] = newValue
    }
  }
}

追加した Environment 変数を使ってみる

上位ビューで Environment 設定

上位ビューコード例

//
//  MyOwnEnvironmentApp.swift
//  MyOwnEnvironment
//
//  Created by Tomoaki Yagishita on 2020/10/19.
//

import SwiftUI

struct MyEnvironmentKey: EnvironmentKey {
  typealias Value = String
  
  static var defaultValue: String = "Default String"
}

extension EnvironmentValues {
  var myEnvironment: String {
    get {
      return self[MyEnvironmentKey.self]
    }
    set {
      self[MyEnvironmentKey.self] = newValue
    }
  }
}

@main
struct MyOwnEnvironmentApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
              .environment(\.myEnvironment, "Non Default String")
        }
    }
}

下位ビューで Environment 参照

Environment 経由で参照

//
//  ContentView.swift
//  MyOwnEnvironment
//
//  Created by Tomoaki Yagishita on 2020/10/19.
//

import SwiftUI

struct ContentView: View {
  @Environment(\.myEnvironment) private var myString
    var body: some View {
        Text(myString)
            .padding()
    }
}

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

environment 変数は mutable?

Environment 変数は、immutable です。

下位ビューから、上位ビューに情報を渡すときには、Preference を使うのが、SwiftUI 流です。

以下の記事で、下位のビューから上位のビューに情報を渡す例を紹介しています。

SwiftUI[SwiftUI]Resizableな画像の特定の位置に表示する

まとめ

Environment 変数を定義する手順
  • EnvironmentKey に準拠するようにキータイプを定義する
  • EnvironmentValues を拡張するように、プロパティとアクセサを定義する

説明は以上です。
不明な点やおかしな点ありましたら、ご連絡いただけるとありがたいです。

SwiftUI おすすめ本

SwiftUI を理解するには、以下の本がおすすめです。

# SwiftUI2.0 が登場したことで少し古くなってしまいましたが、いまでも 定番本です。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です