Swift 28 AppStorageとSceneStorageを使ったSwiftUIデータ持続性

アプリに対する一般的な要求事項中の一つはアフリを一度始めても維持しなければならない少量のデータをアフリが保存するべきものだ。これは使用者の基本設定とか使用者が最後に接近した時の画面に戻るときに有用です。SwiftUIは少量のアフリデータを持続的に保存するための特別な目的を為二つのプロパティラッファー「@AppStorage及び@SceneStorage」を提供します。今度の章にはそれに対して詳しく扱います。

# 二十八・壱 プロパティラッファー
## 壱・一 @SceneStorage
これは個別アフリ画面インスタンス範囲範囲内で少量のデータを保存するために使用されてアフリが実行される間に画面状態を保存して回復するのに以上的です。使用者がアフリ内の様式にで情報を入力する途中、電話とかメセージによって入力が中断されてアフリのブアグランドで下がる状況を考えてみよう。この状態でバックグラウンドであったアフリが終了すれば様式に入力された情報は損失されるはず。だが画面ストレージを使って維持して回復すればこの様な状況を避けるはず。

Scene sotrageは関連された値を保存するために内部的に使用されるキー文字列と一緒に@SceneStorageプロパティをラッファーを使用して宣言されます。例えば次のコードは初期デフォルト値を空文字列で設定する'city'と言う名前を使ってString値を保存する様に設計される画面ストレージプロパティを宣言します。
```diff_swift
@SceneStorage("city") var city: Stirng = ""
```
その様に宣言したなら、保存されたプロパティを次の様にTextEditorと一緒に使うことができます。
```diff_swift
 var body: some View {
        TextEditor(text: $city)
            .padding()
```
こうやってアフリで実装したらアフリを再び初めてもテキストフィールドで入力された全てのテキストが画面ないで指示されます。使用者がiPadOSまたmacOSと同じmulti-windowingフレットプオムで画面についして複数のインスタンスを始じめたら、がく画面には保存された値の固有のコピーを持つようになるだろう。
## 壱・二　@AppStorage
これは各画面ごとに保存されたデータのコピーを持てるる様にします。言い直して一つの画面で保存されたデータはアフリ内の他の画面で接近することができない。@AppStorageプロパティラッファーはアフリ全体を通じて赤んして使われる様にするデータを保存する為に使用されます。

app storageは数年間IOSつか使用できた機能のUserDefaultsを基して構築されました。アフリがデープルト使用者設定で接近して保存する方法で主に提供されるUserDefaultsはアフリで必要な少量のデータをkey-vaule pairの形で保存されるように使用できます。

画面デポー様に@AppStorageプロパティラッファーはキーで使用する文字列値が必要で次の様に宣言します。
```diff_swift
    @AppStorage("mystore") var mytext: String = ""
```
データはデフォルトで標準UserDefaultデポーで保存されます。だがデータを保存するカスタムapp groupを指定できます。アフリグループはアフリが同一なグループ内の他のアフリはたターゲットとデータを共有できるようにします。アフリのグループには名前・一般的にgroup.com.mydomian.myappnameと同じ・が割り当ててXcodeプロジェクトのSigning&Capabilities画面ないで活性されて構成されます。例えば、アフリのグループが活性化されてgroup.com.ebookfrenzy.userdefaultsで名前が設定されたプロジェクトターゲットを見せます。
![Screenshot 2023-12-10 at 3.14.04 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/2cd0e514-de51-0e8a-a816-f522ef0cada5.png)

次の@AppStorage宣言はデータ保存に使用するアプリのグループを参照します。
```diff_swift
@AppStorage("mystore",
                store: UserDefaults(
                suiteName: "group.com.ebookfrenzy.userdefaults")) var mytext: String = ""
```
@Stateプロパティラッファーと同じ様に保存された値を変更すれば新しいデータが反映される様に使用者インタフェイスがリフレッシュされます。

今までアフリデポーと画面保存デポーの元を扱ったから今章の他の部分ではその様なプロパティラッファーがどう動かすかをみって見ましょう。

## 弍・一　StorageDemoプロジェクト生成して準備する
Xcodeを始めてStorageDemoと言う新しいMultiplaform Appプロジェクトを生成しましょう。ContentView.swift ファイルを選択して次の様にTabViewが含まれる様にビューのbodyを変更します。
```diff_swift
  TabView{
            SceneStorageView()
                .tabItem{
                    Image(systemName: "circle.fill")
                    Text("SceneStorage")
                }
            AppStorageView()
                .tabItem{
                    Image(systemName: "square.fill")
                    Text("AppStorage")
                }
        }
    }
}
```
次でFile > New > File.. メニュウを使ってSceneStorageViewとAppStorageViewと言う二つの新しいswiftUI Viewファイルを追加しましょう。
## 弍・二 画面デポーしようる
SceneStorageView.swiftファイルを次の様に修正しましょう
```diff_swift
import SwiftUI

struct SceneStorageView: View {
    
    @State private var editorText: String = ""
    
    var body: some View {
        TextEditor(text: $editorText)
            .padding(30)
            .font(.largeTitle)
    }
}
```
ここで使用するTextEditorビューはSwiftUIアフリないで複数のテキストを表示して編集することができるように設計されたビューで表紙されたテキストが見える領域を越えればスクロルを含まれます。TextEditorビューは、どんなタイプのテキストが保存される状態プロパティに対するバインディングを伝達します。・まだ画面デポーを使用しなかった点を注目してましょう・

コードを修正したらデーバイスとかシミュレーターでアフリをビュルドして実行しましょう。TextEditorビューで少しのテキストを入力します。デバイスのホーム画面が表示されるようにアプリをバッグラウンドで送ったあとXcodeツールバーである中止ボタンを押してアプリを終了しましょう。

アフリを再び実行して以前に入力したテキストがTextEditorビューで回復しなかったことを確認しょう。このアフリで画面デポーを使用すれば確かに役に立ちだろう。

SceneStorageView.swiftファイルに戻って次の様に@Stateプロパティを@SceneStorageプロパティで変更しましょう。
```diff_swift
@SceneStorage("mytext") private var editorText  = ""
```
アフリをまた実行して少しのテキストを入力しした後、バッグラウンドに送った後でアフリを終了します。そしたらアフリをまた実行すると、今度はテキストがTextEditorビューで回復されるようだ。

画面でポーで作業する時、画面の各インスタンスには他の画面と完全に分利された自体デポーがあることを覚えましょう。これを実際経験する為に、アイフェードデバイスとかシミュレーターでStorageDemoアフリを横方向に実行しましょう。アフリが
実行されると画面上段中央にある三つの点を押してspilt viewメニュウオプションを選択します。![Screenshot 2023-12-10 at 9.45.22 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/ca23782b-887e-de84-c864-d4502f3abbe6.png)

## 弍・三　アフリデポー使用
AppStorageView.swiftファイルを次の様に修正しましょう。
```diff_swift
import SwiftUI

struct AppStorageView: View {
    @AppStorage("mytext") var editorText: String = "Sample Text"
    
    var body: some View {
        TextEditor(text: $editorText)
            .padding(30)
            .font(.largeTitle)
    }
}
```
コードを変更したら、アイフェードで更にアフリを実行して二つの画面インスタンスを並んで表示される様に作ります。二つの画面でAppStorageターフを選んで画面インスタンスで基本さんフルテキストが表示されるかを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/f005391e-f74d-5ea9-e63e-4fe76d78c785.png)

弍・四　カスタムターフ保存する
@AppStorageと@SceneStorageプロパティラッファーは特定ターフ値に限って保存することを許容します。特にBool,Int,Double,String,URL及びDataターフ、つまり他のターフを保存しなければならなければ、まずスイフトのデータオブジェクトでエンコードしないと保存するし持ってくる時にデコードされます。
```diff_swift
struct UserName{
    var firstName: String
    var secondName: String
}

var username = UserName(firstName: "Mark", secondName: "Willson")
```
    UserNameは支援されるターフではないからusernameインスタンスをアフリまたは画面ベースのリポジトリに直接に保存することができない。代わりに保存する前にDataインスタンスでエンコーデングしてカプセル化するべきです。エンコーデングとデコーディング実行する正しい段階は保存されるデータターフによって違う。だが核心は該当タープがEncodableとDecodableプロトコルを遵守しなければならないということです。例えば次の様と同じです。
```diff_swift
+ struct UserName: Encodable, Decodable{
    var firstName: String
    var secondName: String
}

var username = UserName(firstName: "Mark", secondName: "Willson")
```
次の例題でJSONエンコーダを使ってusernameインスタンスをエンコーデングして@AppStorageプロパティをラッファーを使用して保存します。
```diff_swift
let encoder = JSONEncoder()
    
    if let data. = try? encoder.encode(username){
        namestore = data
    }
```
貯蔵所でデータを持って来ればJSONデーごだを使用して作業を反対にします。
```diff_swift
 if let name = try? decoder.decode(UserName.self, from: namestore){
        username = name 
    }
```
この技術を使用すると、貯蔵所プロパティラッファーの中で一つを使用してイメージを保存することもできます。
#要約
@SceneStorageと@AppStorageプロパティラッファーはSwiftUIアプリの内で少量のデータを持続的に保存する二つの方法を提供します。scene storageは主にバッグラウンドでアフリが終了される時画面の状態を保存して復元するためのものです。アフリ内の各画面にはアフリの他のエリアで直接に接近することができない独自のローカル画面リポジトリがあります。app storageはUserDefaultsシステム使用してアフリ内でどこでも接近するこがとができるデータを保存する為に使用されます。app groupを使用すれば、同一なアフリプロジェクト内の他のターゲット間にまたは完全に他のアフリ間にアフリリポジトリを共有することもできる。アフリリポジトリに対する変更はアフリの現在プーグランドであるかそれともバッグランドであるかで関係なくで直ちに適応されます。

@AppStorageと@SceneStorageプロパティラッファーはBool, Int,Double,String, URL 及びデータターフに対する保存を支援します。他のターフのリポジトリで配置される前にDataオブジェクトでエンコーデング及びカプセル化するべきです。