[SwiftUI] @AppStorage を使った View State 復元

SwiftUI2021

@AppStorage の使い方の一例を紹介します。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Big Sur 11.4
  • Xcode 12.5
  • iOS 14.5

@AppStorage

@AppStorage は、iOS14/macOS11 から導入されました。

UserDefaults からの読み込みや UserDefaults への書き込みを簡単に行うための Property Wrapper です。

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

UserDefaults

UserDefaults は、SwiftUI 以前から存在して アプリのちょっとしたデータを保存するための領域として使うことができます。

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

保存されたデータは、アプリのライフサイクルを超えて読み書きすることができます。

@State 変数

@State は、SwiftUI と同時に導入された Property Wrapper の1つで、宣言された変数は、その変数を保持するビューのライフサイクルと合わせて管理してくれます。

@AppStorage の使い道

@AppStorage の使い方の一例として、ビューのライフサイクルを超えてデータを保持させることがあります。

ビューのライフサイクルでのみ保存されるケース

以下は、カウンターのサンプルです。
見てもらうとわかりますが、カウンターの値を ビュー内の @State 変数で定義しているため、カウンターのビューが非表示になると、カウンターのデータ自体も失われます。

使用したコードは、以下です。


//
//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2021/06/16
//  © 2021  SmallDeskSoftware
//

import SwiftUI

struct ContentView: View {
    @State private var showCounter = false
    var body: some View {
        VStack {
            if showCounter {
                CounterView()
                    .padding()
            } else {
                Text("counter will appear here")
                    .padding()
            }
            Button(action: {
                showCounter.toggle()
            }, label: {
                Text(showCounter ? "Hide Counter" : "Show counter")
            })
        }
    }
}

struct CounterView: View {
    @State private var counter = 0
    var body: some View {
        VStack {
            Text("\(counter)")
                .font(.largeTitle)
            HStack {
                Button(action: {
                    counter += 1
                }, label: {
                    Image(systemName: "plus")
                })
                Button(action: {
                    counter -= 1
                }, label: {
                    Image(systemName: "minus")
                })
            }
        }
    }
}

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

このような時に、@AppStorage を使用すると ビューのライフサイクルを超えて データを保持することができます。

@AppStorage を使用した データの保持


//
//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2021/06/16
//  © 2021  SmallDeskSoftware
//

import SwiftUI

struct ContentView: View {
    @State private var showCounter = false
    var body: some View {
        VStack {
            if showCounter {
                CounterView()
                    .padding()
            } else {
                Text("counter will appear here")
                    .padding()
            }
            Button(action: {
                showCounter.toggle()
            }, label: {
                Text(showCounter ? "Hide Counter" : "Show counter")
            })
        }
    }
}

struct CounterView: View {
    @AppStorage("counter") private var counter:Int = 0
    var body: some View {
        VStack {
            Text("\(counter)")
                .font(.largeTitle)
            HStack {
                Button(action: {
                    counter += 1
                }, label: {
                    Image(systemName: "plus")
                })
                Button(action: {
                    counter -= 1
                }, label: {
                    Image(systemName: "minus")
                })
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
注意
@AppStorage で指定している "counter" は、アプリケーション内でユニークな値が設定される必要があります。実際に、この値は UserDefaults のキーとして使用されます。つまり、同じキーを使用して他のビューからもアクセスすることが可能であるため、注意が必要です。

まとめ:@AppStorage を使って、ビューのライフサイクルを超えて値を保持する

@AppStorage を使って、ビューのライフサイクルを超えて値を保持する
  • @State を @AppStorage に置き換えるだけで、ビューのライフサイクルを超えて値を保持できる
  • @AppStorage は、UserDefaults を使用してデータを保持する
  • @AppStorage 指定する時には、UserDefaults でのキー値が必要
  • 同じキー値を指定すると別のビューからも操作できてしまうので注意

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

コメントを残す

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