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

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

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

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

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

2822閲覧

【Swift】UserDefaultsに、自分で定義した構造体の配列の値を格納し、取得したい

sta_sato

総合スコア2

iOS

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

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2021/01/17 06:43

編集2021/01/17 06:43

【やりたいこと】複数画面に渡って共通の配列の値を参照・更新をかけることができるように、UserDefaultsへ、配列の値を格納し、取得するコードを組みたいです。また、配列は自分で定義した構造体の型で定義しています。

下記の方法で実現を試してみましたが、(3)がうまく行きません。(下記詳細)

【処理概要】
(1)構造体:foodの定義

(2)food型の配列に値を入れ、UserDefaultsへ格納する

(3)UserDefaultsから、(2)で登録した値を取得する

※本来、こういったリストのデータを格納するには、UserDefaultsよりもCoreDataを使う方が良いという理解をしていますが、今回は練習でUserDefaultsを使っています。

【コード】
(1)構造体foodの定義

Swift

1struct food :Codable{ 2 var nameJP : String 3 var buyDate : String 4 var volume : Int 5 var imageName : String 6} 7

(2)food型の配列に値を入れ、UserDefaultsへ格納する

Swift

1 2import UIKit 3 4class Cabin:UIViewController, UITableViewDelegate, UITableViewDataSource{ 5 6 //UseDefaultsに入れたい配列 7 var InputFoodlist:[food]=[ 8 food(nameJP: "牛乳", buyDate:"20200101", volume: 1, imageName: "milk"), 9 food(nameJP: "卵", buyDate: "20200106", volume: 5, imageName: "egg"), 10 food(nameJP: "豚肉", buyDate: "20210301", volume: 2, imageName: "meat(pig)") 11 ] 12 //UserDefaultsから取得した値を格納するFoodList 13 var Foodlist:[food] = [] 14 15 let userDefaults = UserDefaults.standard 16 17 override func viewDidLoad() { 18 19 super.viewDidLoad() 20 //UserDefaultに、値を入れる 21 Inputlist() 22 //UserDefaultから値を取得数 23 getFoodlist() 24 } 25 26  //UserDefaultsへ値を格納するメソッド 27 func Inputlist(){ 28 let encoder = JSONEncoder() 29 if let encodedValue = try? encoder.encode(InputFoodlist){ 30 UserDefaults.standard.set(encodedValue, forKey: "default") 31 } 32 } 33

(3)UserDefaultsから、(2)で登録した値を取得する

Swift

1 func getFoodlist(){ 2 /// 読み込み 3 if let savedValue = UserDefaults.standard.data(forKey: "default") { 4 let decoder = JSONDecoder() 5 if let value = try? decoder.decode(food.self, from: savedValue) { 6 //ぶち込んだFoodlistの値が取れて欲しい 7 print("UserDefaultsを取得") 8 print(value) 9 } 10 else { 11 print("値取れてない") 12 } 13 } 14 } 15

発生している問題・エラーメッセージ

上記処理を実行するとgetFoodlistメソッドのelseの方の処理が実行され、、"値取れていない"と出力される(=正しくUserDefaultsから値が取れていない)状態となってしまします。 初心者なりの見当違いかもしれないのですが、恐らくUserDefaultsからdecodeして取得する値と、 それを受け取る箱の型が一致していないことが原因なのかと考えているのですが、 仮にそうであった場合、どのように修正したら良いかがネットの記事等を見てもわからなかったです。 原因と、対処案をご教示いただけますと大変助かります。 また、【やりたいこと】に対して、より良い実現方法等あればオプションとして教えていただけると大変大変助かります。 よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

恐らくUserDefaultsからdecodeして取得する値と、
それを受け取る箱の型が一致していないことが原因なのかと考えているのですが、

encoder.encode(InputFoodlist) の引数 InputFoodlist の型は food の配列 (つまり [food]) なのに対して、decoder.decode(food.self, from: savedValue) で変換する型は food.self つまり配列ではない単なる food 型を指定しているためですね。これを [food].self に変更すれば取得できると思います。

また、【やりたいこと】に対して、より良い実現方法等あればオプションとして教えていただけると大変大変助かります。

勉強中ということでとりあえず UserDefaults で構わないと思いますが、いずれは Core Data なども使えるようになると良いと思います。Core Data 以外の選択肢は、自分でファイルや SQLite に保存する、Core Data の代わりに Realm を使う、Firebase などのクラウドストレージを利用する、などの方法があります。

また、余計なお世話かとは思いますが、型や変数やメソッドの名前の付け方が気になりました。Swift の命名規則では、型やクラスの名前は大文字、変数やメソッドの名前は原則として小文字で始めることになっていますので、次のように修正することをお勧めします。

  • struct food → struct Food
  • var InputFoodlist → var inputFoodlist
  • var Foodlist → var foodlist
  • func Inputlist → func inputlist

また、Cabin というクラス名も CabinViewController とするのが一般的かと思います。(Cabin という名前は純粋なデータ型のために取っておきたいので。)

参考: 【Swift】命名規則や書き方など まとめ | Swift Note
参考: Swiftの命名規則を理解する(Swift API Design Guidelines - Naming 日本語まとめ) - Qiita

投稿2021/01/17 07:55

hoshi-takanori

総合スコア7895

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

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

sta_sato

2021/01/17 14:15

ありがとうございます。ご指摘の通り、変換先の型を変更したら無事実装できました。 データを入れた時の型と、取り出して値を入れる型が合っていないので、取得できていなかったのだと理解しました。 Core Dataや、外部DBを使った値の受け渡しについても、チャレンジしていきたいと思っています。 また、変数名についても、アドバイスありがとうございます。命名規則はなんとなくでしか分かっていなかったですので、参考のリンクは大変助かります。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問