🕌

【Swift5】UserDefalutsで自作データモデル配列を保存した後に既存ユーザーに影響を与えずにデータモデルのプロパティを追加したい

2022/03/04に公開

今回やりたいこと

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