質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Q&A

解決済

3回答

4758閲覧

UserDefaultsの削除とSwiftUIでのViewの更新について

yotubarail

総合スコア23

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

0グッド

1クリップ

投稿2020/07/20 04:19

配列の中身をListで表示し、順番を入れ替えたり削除したりした後にUserDefaultsに保存するようにしています。
UserDefaultsの中身が変わるとViewを更新できるようにしたいと考えています。
removeObjectでUserDefaultsでの削除を行った際にViewを更新する方法がわからず、質問させていただきました。
アプリを再起動するとremoveObjectが効いていて、データの削除ができていることは確認できました。

swift

1struct listUserDefaultsView: View { 2 3 @ObservedObject var useList = useUserDefaults() 4 5 var body: some View { 6 List { 7 Section(header: Text("入れ替えも削除も可能なリスト")) { 8 ForEach(useList.phones, id: .self) { phone in 9 HStack { 10 Image("logo") 11 .resizable() 12 .frame(width: 20, height: 20) 13 Text(phone) 14 }.id(UUID()) 15 } 16 .onMove(perform: useList.phoneReplace) 17 .onDelete(perform: useList.phoneDelete) 18 } 19 } 20 .navigationBarTitle("UserDefaultsを用いたリスト", displayMode: .inline) 21 .navigationBarItems(leading: Button("データ消去") { 22 self.useList.userDefaultsRemove() 23 },trailing: EditButton()) 24 .onAppear() { 25 guard let phoneItem = UserDefaults.standard.array(forKey: "phoneRow") as? [String] else { 26 return 27 } 28 self.useList.phones = phoneItem 29 } 30 } 31} 32 33class useUserDefaults: ObservableObject { 34 35 let key = "phoneRow" 36 let defaults = UserDefaults.standard 37 38 @Published var phones = ["iPhone", "ZenFone", "Google Pixel"] 39 40 func phoneReplace(_ from: IndexSet, _ to: Int) { 41 phones.move(fromOffsets: from, toOffset: to) 42 defaults.set(phones, forKey: key) 43 } 44 45 func phoneDelete(offsets: IndexSet) { 46 phones.remove(atOffsets: offsets) 47 defaults.set(phones, forKey: key) 48 } 49 50 func userDefaultsRemove() { 51 defaults.removeObject(forKey: key) 52 } 53 54}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

UserDefaultsのデータを消す処理を行っても初期値が消えないようにできないかと考えました。

UserDefault.register(defaults:)は知らなかったので、大変勉強になりました。ありがとうございます。

なお、初期化が少し気になりました。
registerの初期化とuserdefaultsの初期化の順序に依存性がありますが、Swiftのプロパティのデフォルト値の初期化順序について、コードに登場した順に行われるという保証はないような気がします。

私だったらどうするかを考えてみたので、参考にご紹介します。変数名などは変えないようにしていますが、引数のラベルはありに変えました。

・コンストラクタ(init)を用意して、初期化の問題(?)を回避しました。keyなどの定義も使えてコードがすっきりしました。

・コンストラクタを追加したついでに、UserDefault.standardはシングルトンなので、クラスもシングルトンにしました。同一のリソースに複数のクラスインスタンスからアクセスする際に起こる問題を回避するためです。この場合、UseUserDefaults.shared.userDefaultsRemove()というような感じで使えます。

final class UseUserDefaults: ObservableObject { static var shared: UseUserDefaults = UseUserDefaults() @Published var userdefaults: [String] = [] private let key = "phoneKey" private let defaultPhoneList = ["iPhone", "ZenFone", "Google Pixel"] private let defaults = UserDefaults.standard private init() { defaults.register(defaults: [key: defaultPhoneList]) loadUserDefaults() } private func loadUserDefaults() { userdefaults = defaults.stringArray(forKey: key)! // デフォルト値を登録しているので、nilになることはない } func phoneReplace(from: IndexSet, to: Int) { userdefaults.move(fromOffsets: from, toOffset: to) defaults.set(userdefaults, forKey: key) } func phoneDelete(offsets: IndexSet) { userdefaults.remove(atOffsets: offsets) defaults.set(userdefaults, forKey: key) } func userDefaultsRemove() { defaults.removeObject(forKey: key) loadUserDefaults() } }

投稿2020/07/22 01:59

eytyet

総合スコア803

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

eytyet

2020/07/22 02:01

あらら。yotubarailさんの回答へのコメントのつもりで書いたのに、誤って別の回答として投稿してしまいました。読みにくくてすいません。
yotubarail

2020/07/22 04:23

初期化に関しては自分も書きながら気になっていたところでした。 イニシャライザを用いた方法に変更しようと思います。 今後同じような課題を抱えてアクセスされる方には回答という形式の方が課題への提案の1つとしてわかりやすいかなと思います。 ありがとうございます。
guest

0

回答がありましたが、phonesの配列を空にすることで最初に入力されてあったものは消えてしまいます。
そこで、UserDefaultsのデータを消す処理を行っても初期値が消えないようにできないかと考えました。

swift

1class UseUserDefaults: ObservableObject { 2 3 let key = "phoneKey" 4 let defaults = UserDefaults.standard 5 6 let register: Void = UserDefaults.standard.register(defaults: ["phoneKey": ["iPhone", "ZenFone", "Google Pixel"]]) 7 8 9 @Published var userdefaults = UserDefaults.standard.stringArray(forKey: "phoneKey") 10 11 func phoneReplace(_ from: IndexSet, _ to: Int) { 12 userdefaults!.move(fromOffsets: from, toOffset: to) 13 defaults.set(userdefaults!, forKey: key) 14 } 15 16 func phoneDelete(offsets: IndexSet) { 17 userdefaults!.remove(atOffsets: offsets) 18 defaults.set(userdefaults!, forKey: key) 19 } 20 21 func userDefaultsRemove() { 22 defaults.removeObject(forKey: key) 23 guard let phoneItem = defaults.stringArray(forKey: key) else { 24 return 25 } 26 self.userdefaults! = phoneItem 27 } 28 29 30}

UserDefaultsの初期値として配列を入れました。
UserDefaults内の変化に応じて画面が更新されるようになりました。

ご回答いただきましたeytyetさん、ありがとうございました。

投稿2020/07/21 08:10

yotubarail

総合スコア23

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

func userDefaultsRemove() { defaults.removeObject(forKey: key) phones.removeAll() // この行を追加 }

phonesを空の配列にすれば、画面が更新されると思います。

蛇足ですが、クラス名は大文字で始めるお約束なので、useUserDefaultsUseUserDefaultsにした方がよいですよ。

投稿2020/07/21 07:14

eytyet

総合スコア803

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yotubarail

2020/07/21 07:36

確かにその通りでした。 class名の件うっかりしておりました。 ご指摘いただきありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問