Closed tas5521 closed 6 months ago
@YoshinoriKobayashi @FromF Pickerの状態をCoreDataではなくUserDefaultsに保存する案をくださり、ありがとうございました🙏 作成していただいたPR (#106)を参考に、コードを修正しました。 ほとんど、提供していただいた例に倣っていますが、下記の点で異なっています。
ModeSelectionViewModelの拡張により追加するUserSelection構造体は、Encodable, Decodable
というように分けず、Codable
に準拠しました。また、questionListID
はUUID型であり、UUID型はCodableに準拠しているので、そのまま使用できるのではないかと思い、String?
型ではなくUUID
型にしました。
https://github.com/CodeCandySchool/MedicineNameQuiz_Sagae/blob/95ca00cd2e44df62a9e7dafec4dcd0c4b58735f0/MedicineNameQuiz_Sagae/ViewModel/ModeSelectionViewModel.swift#L109-L115
userDefaultsKey
は、 setting
ではなく、userSelection
にしました。
https://github.com/CodeCandySchool/MedicineNameQuiz_Sagae/blob/95ca00cd2e44df62a9e7dafec4dcd0c4b58735f0/MedicineNameQuiz_Sagae/ViewModel/ModeSelectionViewModel.swift#L38-L39
loadUserSelectionメソッドでは、if letのネストが深いように感じたので、guard letを使用しました。また、questionListIDはString?型ではなくUUID型にしたので、アンラップしなくなりました。 https://github.com/CodeCandySchool/MedicineNameQuiz_Sagae/blob/95ca00cd2e44df62a9e7dafec4dcd0c4b58735f0/MedicineNameQuiz_Sagae/ViewModel/ModeSelectionViewModel.swift#L91-L107
ModeSelectionViewの.onAppear
では、if文の処理が消されていましたが、これは残しました。理由は、以下の操作をしたときにクラッシュしてしまうのを避けるためです。
<クラッシュする操作>
このクラッシュを回避するため、指定されたIDの問題が問題リスト(fetchedLists)にない場合に、リストの一番上の問題リストをセットしています。また、この時にも選択されているPickerが変わるため、UserDefaultsへの保存を行っています。 https://github.com/CodeCandySchool/MedicineNameQuiz_Sagae/blob/95ca00cd2e44df62a9e7dafec4dcd0c4b58735f0/MedicineNameQuiz_Sagae/View/Study/ModeSelectionView.swift#L138-L153
ご検討をお願いいたします🙇♂️
@FromF ご提案をありがとうございました! UserDefaultsKeys列挙型を作成し、型から静的変数を呼び出すようにしました。 https://github.com/CodeCandySchool/MedicineNameQuiz_Sagae/blob/763364537e1c6c4172ab29829359c893dce57c60/MedicineNameQuiz_Sagae/Model/UserDefaultsKeys.swift#L10-L12 https://github.com/CodeCandySchool/MedicineNameQuiz_Sagae/blob/763364537e1c6c4172ab29829359c893dce57c60/MedicineNameQuiz_Sagae/ViewModel/ModeSelectionViewModel.swift#L83-L84
一つ気になったのですが、下記のように構造体でも可能かと思いますが、構造体でも列挙型でも、どちらでも良いのでしょうか?
struct UserDefaultsKeys {
static let userSelection = "userSelection"
}
Enumの方が良い理由等がありましたら、知りたいです🙏
@tas5521
まず、wikipediaをそれぞれの定義を確認してみましょう。
構造体 "構造体(こうぞうたい、英: structure)はプログラミング言語におけるデータ型の一つで、1つもしくは複数の値をまとめて格納できる型" とされています。 一般的には、値を束ねる(変数の集まりのイメージ)ために構造体を用いると考えています。
列挙型 "列挙型(れっきょがた、enumerated typeあるいはenumeration type)とは、コンピュータプログラミングにおいて、プログラマが選んだ各々の識別子(列挙子)をそのまま有限集合として持つ抽象データ型である" とあります。 有限集合は、とりうる値の集まりということだと考えています。
今回の目的は、UserDefautlsのキーを管理する目的で提案しました。これは、とりうるキーを一元管理することだと考えていますので、有限集合となるのではないかと考えていて、そこで列挙型(enum)を選択しました。
@FromF ご提案をありがとうございました! UserDefaultsKeys列挙型を作成し、型から静的変数を呼び出すようにしました。
一つ気になったのですが、下記のように構造体でも可能かと思いますが、構造体でも列挙型でも、どちらでも良いのでしょうか?
struct UserDefaultsKeys { static let userSelection = "userSelection" }
Enumの方が良い理由等がありましたら、知りたいです🙏
関連Issue番号
close #92
追加・変更の概要
学習画面の、問題リスト選択、および、モード選択のPickerを、前回選択した位置からスタートするようにします。
変更の目的
前回選択した位置からスタートできるとユーザーにとって便利であると思われるため。
タスクの進捗状況
変更内容
initializeUserSelection
を追加しました。ModeSelectionViewの.onAppear
内で、初めてModeSelectionViewが表示された時に、このメソッドを実行し、CoreDataにPickerの選択状態を管理する領域を確保します。saveUserSelection
を作成しました。各Pickerの値が変更された時に、.onChange
により、このメソッドを実行し、CoreDataに状態を保存します。loadUserSelection
を追加しました。ModeSelectionViewの.onAppear
内で、2回目以降(CoreDataにPickerの選択状態を管理する領域が存在する状態で)、ModeSelectionViewが表示された時に、このメソッドを実行し、Pickerの選択の状態を読み込みます。StudyMode
型のプロパティmodeSelection
で管理していましたが、modeSelection
という名前がわかりにくいので、studyMode
に変更しました。initializeUserSelection
を実行するとUserSelectionに第一要素が作成されますが、ユーザーにはUserSelectionの要素を削除する方法は提供しません。しかし、開発上デバッグ等の際にUserSelectionの要素を削除できないと不便なので、UserSelectionの要素を全て削除するメソッドdeleteUserSelection
をコメントに残しています。影響範囲
操作方法
テストしたこと
上記を確認しました。
相談事項
CoreDataに保存したいPickerの状態は3つありますが、全て
saveUserSelection
でまとめて行っています。そのため、一つのPickerの値が変わったときに、他の2つは変化がないにも関わらず、保存処理が行われてしまいます。これが問題なければ、どのPickerでもsaveUserSelection
の一つのメソッドを実行すれば良いので楽なのですが、各Pickerごとに別々の処理にした方が良いでしょうか? よろしくお願いします。