スポンサーリンク

[SwiftUI]UserDefaultsでデータ永続化

このページには広告が表示されます。
スポンサーリンク

サンプルアプリでCoreDataを使ったデータの永続化は試してみましたが、今回はUserDefaultの話です。

スポンサーリンク

UserDefaultとは

デフォルトの情報、つまりアプリの設定情報やユーザーの設定など、一度セットして毎回使うような情報を保存したい時に使います。

(データベースが作られるわけじゃないので、どんどん増えていくデータなどの保存には向きません。)

UserDefaultsのデータはアプリのローカル保存領域に保存され、アプリ起動時に呼び出されるそうな。

保存方法はUserDefaultsで設定する方法と、@AppStrageで設定する方法があるみたいなので、今回は同じ挙動になるように両方のコードを試してみたいと思います。

ちなみに配列、辞書、Any型など一部のデータ型は@AppStrageでは扱えません。

開発環境バージョン
Xcode12.5.1
iOS14.0以降
macOSBigSur 11.5.2

MVVM風にUserDefaultsを使ってみる

入力したデータがViewに即時反映できるように、MVVM風にUserDefaultを使ってみようと思います。
設定したい項目が多い時にはデータとViewを分けた方が使いやすいですよね。

作成・編集するファイル
  • [編集]ContentView.swift
    Viewのファイル
  • [作成]ProfileData.swift
    UserDefaultsのデータモデルのファイル
入力欄に入力すると
下に自動で表示されます

入力後も何度でも自由に編集できて、かつアプリを再起動してもデータが消えません。

今回UserDefaultsに保存するのは、String型の身長、体重、年齢の入力データです。
Textfieldに入力されたものをUserDefaultsに保存し、アプリ再起動でもデータが消えないようにします。

ContentView.swift

//
//  ContentView.swift
//  UserdefaultsSample
//
//  Created by Yaguchi Sato on 2021/12/09.
//

import SwiftUI

struct ContentView: View {
    @StateObject private var profile = ProfileData()

    var body: some View {
        VStack(alignment: .center){
//UserDefaultsに入力保存
                TextField("身長", text: $profile.bodyHeight)
                TextField("体重", text: $profile.bodyWeight)
                TextField("年齢", text: $profile.Age)
 //UserDefaultsのデータを表示
                Text("身長:\(profile.bodyHeight) cm")
                Text("体重:\(profile.bodyWeight) kg")
                Text("年齢:\(profile.Age) 歳")
        }.textFieldStyle(RoundedBorderTextFieldStyle())
    }
}
    


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

ProfileData.swift UserDefaultのデータモデル

UserDefaultは、値とキー(String型)をセットで保存して、キーで値を呼び出す仕組みです。
データモデルで、保存するデータの型とキー、初期値をセットします。

//
//  ProfileData.swift
//  UserdefaultsSample
//
//  Created by Yaguchi Sato on 2021/12/09.
//

import SwiftUI
//クラスをObservableObjectとして定義
class ProfileData :ObservableObject{
//UserDefaults.standard.set(変数名,  forkey: "Stringのキー")
    @Published var bodyHeight: String {
        didSet {UserDefaults.standard.set(bodyHeight, forKey: "bodyHeight")}}
    @Published var bodyWeight: String {
        didSet {UserDefaults.standard.set(bodyWeight, forKey: "bodyWeight")}}
    @Published var Age: String {
        didSet {UserDefaults.standard.set(Age, forKey: "Age")}}

    //初期化する
    init(){
        bodyHeight = UserDefaults.standard.string(forKey: "bodyHeight") ?? ""
        bodyWeight = UserDefaults.standard.string(forKey: "bodyWeight") ?? ""
        Age = UserDefaults.standard.string(forKey: "Age") ?? ""
    }
}

「init()」の「??」の後にデフォルトの値をセットすることができます。(サンプルは空欄)
UserDefaultには、data/bool/integer/float/double/URL/配列/辞書など、String以外のデータ型も保存できますよ。

というか今回のやつIntでもよかったなってちょっと思った。
Stringなら漢数字も入れられるしまぁこれはこれでいっか……

AppStrageでUserDefaultsに保存

次はiOS14から使える@AppStrageというプロパティラッパーを試してみます。
@Stateのようにデータを監視して変更を反映しつつ、UserDefaultsの値を扱えるということなんですが、どうかな。

アプリの挙動は全く同じで、Textfieldに入力された値をUserDefaultsに保存して表示します。

編集するファイル
  • [編集]ContentView.swift
    @AppStrageの場合はデータモデルファイルは使いません。
//
//  ContentView.swift
//  UserdefaultsSample
//
//  Created by Yaguchi Sato on 2021/12/09.
//

import SwiftUI

struct ContentView: View {
//@AppStorage(wrappedValue:"初期値","キー") private var 変数名:データ型
    @AppStorage(wrappedValue: "", "bodyHeight") private var bodyHeight: String
    @AppStorage(wrappedValue: "",  "bodyWeight") private var bodyWeight: String
    @AppStorage(wrappedValue: "",  "Age") private var Age: String 
        
    var body: some View {
        VStack(alignment: .center){
            TextField("身長", text: $bodyHeight)
            TextField("体重", text: $bodyWeight)
            TextField("年齢", text: $Age)
            
            Text("身長:\(bodyHeight) cm")
            Text("体重:\(bodyWeight) kg")
            Text("年齢:\(Age) 歳")
            
        }.textFieldStyle(RoundedBorderTextFieldStyle())
    }
}
    


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

データモデルファイルは無しで、スッキリしたコードで動作と見た目は全く同じです。

AppStrageは、ひとつのView内だけで使うなら、データ入力時に即時反映でViewが更新されるんですが、別ファイル間で値を渡そうとした場合、再起動しないとViewは更新されませんでした。

MVVMでもっと複雑なデータ構造のアプリを作るなら、ファイル間でデータの変更を感知できるようにコードを組んでUserDefaultsを使った方がいいかも。
単純に一画面で済むような時はAppStrageはとっても使いやすいと思います。

以上!アプリの設定などに使えるUserDefaultsの話でした。


タイトルとURLをコピーしました