この記事では、Buttonなどのアクションを利用せずにUserDefaultsで値を制御する方法を紹介します。
SwiftUIで従来から利用されているLife Cycle のUIKit App Delegate と、iOS14から利用されているSwiftUI App の両方の場合の方法を紹介します。
ログイン、ログアウトなどの処理は、ボタンを押すというはっきりとしたアクション行為があるので、その際にUserDefaultsの処理を行う方法がよくとられます。
一方で、設定の値保持するなどはっきりとした行為がなく(トグルで切り替えを行い保存等のボタンを使用しない)、UserDefaultsの処理をするには、NSObjectProtocolを利用する方法で可能となります。
◆動作検証環境
・XCode:12.1
・SwiftUI:2.0
・Life Cycle:UIKit App Delegate, SwiftUI App(iOS 14.0 -)
UIKit App Delegate
NSObjectProtocolで値の保持、取り出しの処理を行う
ObservableObjectプロトコルに適合させたクラスに下記のコードを追記します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import SwiftUI import Foundation class AccountAPI: ObservableObject { @Published var tokenKey:String = "" ...中略 private var observers = [NSObjectProtocol]() init(){ observers.append( NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main) { _ in if let data = UserDefaults.standard.object(forKey: "data" ){ var value = data as! String } } ) observers.append( NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: .main) { _ in UserDefaults.standard.set("value", forKey: "data") } ) } } |
ポイントは以下のとおり
2行目:
UIApplication を利用するため、SwiftUI をインポートします。
13行目から:
didBecomeActive のライフライクルでUserDefaultsのTokenデータを、@Published変数に入れます
18、19行目:
バックグラウンドからアクティブになる際、ログイン済み(Tokenが発行済み)の場合は、ログイン後の指定のビューに遷移するように対象のフラグとtrueにする。
25行目から:
willResignActive のライフライクルで@Published変数のTokenデータを、UserDefaultsにセットします。
SwiftUI App
Life CicleをSwiftUI App として利用する場合の参考コードは以下のとおりです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import SwiftUI struct ContentView: View { @Environment(\.scenePhase) private var scenePhase @State var appStatus: AppStatus? var body: some View { VStack{ Text("Hello, world!") .padding() } .onChange(of: scenePhase) { newScenePhase in if newScenePhase == .active { appStatus = .active if let data = UserDefaults.standard.object(forKey: "data" ){ var value = data as! String } }else if newScenePhase == .inactive { if appStatus == .active{ UserDefaults.standard.set("value", forKey: "data") }else{ } appStatus = .inactive }else if newScenePhase == .background{ appStatus = .background } } } } enum AppStatus { case active case inactive case background } |
ポイントは以下のとおりです。
6行目:@Environment(\.scenePhase) 変数を定義し、.onChange モディファイアでライフサイクルの応じた処理を可能とさせる。
これにより、active 、inactive 、background の状況に応じて処理を行える
7行目:39行目に定義しているAppStatus 型の変数を利用。
SwiftUI App のinactive の状態は、active →background 、background →active の両方に対応するため、enumを利用して、ライフサイクルの条件を細分化している。
以上、SwiftUIでButtonなどのアクションを利用せずにUserDefaultsで値を制御する方法を紹介しました。