【Swift5】UserDefalutsで自作データモデル配列を保存した後に既存ユーザーに影響を与えずにデータモデルのプロパティを追加したい
今回やりたいこと
class DeckModel: NSObject, NSCoding {
var deckTitle = ""
var duckRecipeId = ""
var createDate = ""
var memo = ""
}
このデータモデルのクラスで運用してきたのですが、
追加でお気に入り機能が欲しくて、
データモデル内でBoolでお気に入り有無(isFav)
を保存しておく必要が今回のアップデートでした。
しかしながら、var isFav = false
のように初期値を宣言すると、*date型をデコード後に「デコードした対象のdateにプロパティisFavがすでに存在していても、いなくてもFalseがセットされる」*という状況になります。(要約:一度保存したboolの値が常にfalseで更新される)
なので、既存ユーザーに影響を与えずにプロパティ追加が出来ないんですよね。
上記変更を加えたアプデ後に起動すると、どれかをお気に入りONにしても、
次回起動時がすべてお気に入りOFFになります。
ポイント1:key:isFavが存在するか確認する
memo = aDecoder.decodeObject(forKey: "memo") as! String //比較例として
if aDecoder.containsValue(forKey: "isFav") {
isFav = aDecoder.decodeBool(forKey: "isFav")
} else {
// isFavが登録されていない
isFav = false
}か
リリース時から存在するプロパティmemo
は確実に格納されているのでチェックは行っておりません。
nilでクラッシュすることはありえません。
.constainsValue(:)
にて、該当するKeyが存在するか確認しています。
存在している場合は値を利用し、存在していない場合ということは、
アップデート後初めての起動となりますのでfalse(初期値)
をセットしてあげてください。
ポイント2:プロパティ宣言時に初期値falseを避ける
class DeckModel: NSObject, NSCoding {
var deckTitle = ""
var duckRecipeId = ""
var createDate = ""
var memo = ""
var isFav = Bool()
このように宣言してください。
ポイント3:しっかりプロパティ追加に伴う追加作業をもれなく行う
これは忘れずに作業を行う系のタスクですね。
init(_ deckTitle: String?, duckRecipeId: String?, createDate: String?, memo: String?, isFav: Bool?) {
self.deckTitle = deckTitle!
self.duckRecipeId = duckRecipeId!
self.createDate = createDate!
self.memo = memo!
self.isFav = isFav! //ADD
}
// NSKeyedArchiverに呼び出されるシリアライズ処理(NSCodingで定義されている)
func encode(with aCoder: NSCoder) {
aCoder.encode(self.deckTitle, forKey: "deckTitle")
aCoder.encode(self.duckRecipeId, forKey: "duckRecipeId")
aCoder.encode(self.createDate, forKey: "createDate")
aCoder.encode(self.memo, forKey: "memo")
aCoder.encode(self.isFav, forKey: "isFav") //ADD
}
追記
こういうアップデートは、うまくいかない場合はアップデート後に全ユーザーにとって影響があり、アプリ起動→クラッシュするので影響範囲が非常に大きいです。
たとえば上記改修をver2.0.0.0で行ったとすれば、
私はver1.X.XでiOSシミュレーターを初期化を行い、そこでデータを構築してから、
ver2.0.0.0で問題ないかを確認してからアップデートをリリースしています。
ちゃんとテストしてからアップデートしましょう。
Discussion