こんちには、フリーのITエンジニアでWeb(PHP:Laravel)のバッグエンドをメインにフルリモートでお仕事させて頂きながら、個人開発でiOSアプリを作っているMoritaです。
個人でアプリを作る場合、少しづつ機能を追加していくため、Realmの更新処理が散乱してしまったので、まとめた方法を紹介します。
検証環境
Xcode:11.4.1
端末:iPhone 7 Plus
iOS:13.4.1
今回の問題点
プロトタイプを作成しながら開発をしているので、機能を追加したときにとりあえずRealmの更新処理をその都度書いていたのですが、モデルのプロパティが増加するたびに全ての箇所を変更しなければならず、変更漏れが発生していました。
(Repositoryを作成してその中でRealmのaddメソッド読んでます。)
let rp: AnyRepository<BookModel> = AnyRepository(VocabularyBookRealmRepository())
let model = BookModel()
model.id = self.bookModel!.id
model.name = self.bookModel!.name
model.frontTextPosition = self.bookModel!.frontTextPosition
model.backTextPosition = self.bookModel!.backTextPosition
model.commentTextPosition = self.bookModel!.commentTextPosition
model.frontTextSize = self.bookModel!.frontTextSize
model.backTextSize = self.bookModel!.backTextSize
model.commentTextSize = self.bookModel!.commentTextSize
model.created_at = self.bookModel!.created_at
model.updated_at = Date()
rp.update(domains: [model])
改善方法
Managerクラスを作成して、その中で更新処理を呼ぶ方法に変更しました。
static func update(bookModel: BookModel) {
let rp: AnyRepository<VocabularyBookModel> = AnyRepository(VocabularyBookRealmRepository())
let model = VocabularyBookModel()
model.id = bookModel.id
model.name = bookModel.name
model.frontTextPosition = bookModel.frontTextPosition
model.backTextPosition = bookModel.backTextPosition
model.commentTextPosition = bookModel.commentTextPosition
model.frontTextSize = bookModel.frontTextSize
model.backTextSize = bookModel.backTextSize
model.commentTextSize = bookModel.commentTextSize
model.created_at = bookModel.created_at
model.updated_at = bookModel.updated_at
model.deleted_at = bookModel.deleted_at
rp.update(domains: [model])
}
呼び出し元で保持しているRealmのモデルのオブジェクトのプロパティを変更して、
このManagerクラスのupdateメソッドに渡して更新しようと考えたのですが、
保持しているRealmのモデルオブジェクトはマネージドオブジェクトになっているため、witeメソッド内で変更しなければエラーが発生します。
そこで、モデルオブジェクトにNSCopyingを継承させて、copyメソッドの中でインスタントの入れ替えをするようにしました。
class BookModel: Object, NSCopying {
@objc dynamic var id: String = NSUUID().uuidString
@objc dynamic var name: String?
@objc dynamic var deleted_at: Date?
@objc dynamic var created_at: Date?
@objc dynamic var updated_at: Date?
let vocabularies = List<VocabularyModel>()
func copy(with zone: NSZone? = nil) -> Any {
let model = VocabularyBookModel()
model.id = id
model.name = name
model.frontTextPosition = frontTextPosition
model.backTextPosition = backTextPosition
model.commentTextPosition = commentTextPosition
model.frontTextSize = frontTextSize
model.backTextSize = backTextSize
model.commentTextSize = commentTextSize
model.created_at = created_at
model.updated_at = updated_at
model.deleted_at = deleted_at
let vocabulaiesRow = vocabularies.map{$0}
let newVocabularies = vocabulaiesRow.map{
vocabulary -> VocabularyModel in
let vocabularyModel = VocabularyModel()
vocabularyModel.id = vocabulary.id
vocabularyModel.book_id = vocabulary.book_id
vocabularyModel.front = vocabulary.front
vocabularyModel.back = vocabulary.back
vocabularyModel.comment = vocabulary.comment
vocabularyModel.isCheck = vocabulary.isCheck
vocabularyModel.isFavorito = vocabulary.isFavorito
vocabularyModel.deleted_at = vocabulary.deleted_at
vocabularyModel.created_at = vocabulary.created_at
vocabularyModel.updated_at = vocabulary.updated_at
return vocabularyModel
}
newVocabularies.forEach{ model.vocabularies.append($0) }
return model
}
プロパティにListを持っている場合も取り出して、再度モデルオブジェクトに入れ直したものでListを作成しています。
呼び出しもとは以下のようになります。
呼び出し元で保持していたモデルオブジェクトに対してcopyメソッドを使用して再度モデルオブジェクトを作成しています。
let model = self.bookModel?.copy() as! BookModel
model.name = "test"
RealmManager.update(bookModel: model)
まとめ
めんどくさくなてRealmの更新処理をコピペで量産していたら、プロパティのコピー忘れでデータ不整合が起きて無駄に原因調査の時間がかかってしまいました。
やばそうだと思った時に早めに対応しておく方が後々やっぱりいいですね。
コメント