로아랑 프로젝트 진행 중 Realm에 저장되는 객체에 대한 수정 사항이 생겼다
물론 아직 출시 전이라 수정하고서 그냥 어플 삭제하고 다시 빌드하면 되지만 만약 출시를 했다고 가정했을 때 이렇게 DB모델에 수정사항이 생긴다면 마이그레이션을 필수이기에 출시 전 이에 대해 알아보았다
몽고DB의 홈페이지를 보면 마이그레이션 방법에는 크게 두 가지 방법이 있는 것 같은데(아마도?)
첫 째는 간단한 속성 추가나 제거와 같은 경우 사용 할 수 있는 방법이고
둘 째는 조금 복잡한 상황(이미 정해져있는 이름이나 타입의 변경등의 상황에 사용할 수 있는 방법)에서 migrationBlock
을 이용하는 방법인데 이 부분은 추후 공부하고 새로 포스팅을 작성해볼 예정이다
1번 방법은 방법은 너무나도 간단하다
로아랑의 경우, Realm을 SceneDelegate에서 생성해 주입해주고 있으며 기존 코드는 아래와 같다
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.makeKeyAndVisible()
guard let realm = try? Realm() else {
window?.rootViewController = UIViewController()
window?.rootViewController?.showExitAlert(message: "앱 저장소 오류가 발생했습니다.\n앱 재설치 혹은 고객센터로 문의 부탁드립니다.")
return
}
let container = Container(storage: AppStorage(LocalStorage(realm: realm)))
let navigationController = UINavigationController(rootViewController: TabBarViewController(container))
navigationController.isNavigationBarHidden = true
window?.rootViewController = navigationController
}
}
여기서 configuration을 담는 프로퍼티를 만들어주고 그걸 Realm에 할당만 해주면 된다
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.makeKeyAndVisible()
//추가
let config = Realm.Configuration(schemaVersion: 0)
Realm.Configuration.defaultConfiguration = config
guard let realm = try? Realm() else {
window?.rootViewController = UIViewController()
window?.rootViewController?.showExitAlert(message: "앱 저장소 오류가 발생했습니다.\n앱 재설치 혹은 고객센터로 문의 부탁드립니다.")
return
}
... 이하 생략 ...
final class BookmarkUserDTO: Object {
@Persisted(primaryKey: true) var name: String
@Persisted var imageData: Data
@Persisted var `class`: String
var convertedInfo: BookmarkUser {
return BookmarkUser(name: self.name,
image: UIImage(data: imageData) ?? UIImage(),
class: self.`class`)
}
}
현재 BookmarkUserDTO
는 위와 같이 정의되어 있는데 만약 여기서 guild
라는 프로퍼티가 추가적으로 필요한 상황이라고 가정해보자
final class BookmarkUserDTO: Object {
@Persisted(primaryKey: true) var name: String
@Persisted var imageData: Data
@Persisted var `class`: String
//추가
@Persisted var guild: String
var convertedInfo: BookmarkUser {
return BookmarkUser(name: self.name,
image: UIImage(data: imageData) ?? UIImage(),
class: self.`class`)
}
}
이렇게 프로퍼티만 추가하고 실행시키면
아예 실행 단계에서 realm 오류가 발생해 지정해준 얼럿을 띄우게 된다
let config = Realm.Configuration(schemaVersion: 1)
그런데 1번과정에서 추가해준 스키마 버젼을 위와 같이 올려주기만 하면 정상 실행 된다
아직 guild에 대한 값을 넣는 로직을 만들지 않아 값은 없지만 Realm Studio를 확인 해도 추가 된 모습이다
반대로 다시 guild프로퍼티를 제거하고 스키마 버젼을 다시 한단계 높여 2로 수정하면
이렇게 사라진 모습이다
사용자가 유저를 검색을 했을 때 최근 검색 기록을 가져오기 위해 RecentUserDTO
라는 객체를 추가할 일이 있어
final class RecentUserDTO: Object {
@Persisted(primaryKey: true) var name: String
@Persisted var itemLV: String
@Persisted var `class`: String
}
위와 같은 모델을 만들어줬는데 이 때는 스키마 버젼을 올려주지 않아도 정상적으로 추가되었다
바로 위에서 만들어준 RecentUserDTO
라는 모델을 사용할 일이 없어져서 제거 했을 때 xcode내에서는 RecentDTO는 없는 것이지만 Realm Studio에는
없어져야 할 요녀석이 계속 있다...
이 부분은 차차 알아가봐야겠다...!
사실 지금단계에서는 필요 없는 내용이긴하다
어차피 출시할때는 스키마 버젼 0으로 출시를 할 것이고 사용자들은 그 때 새로 설치를 하게 될 것이기 때문이다
그럼에도 나중에 기능이 추가되면서 새로운 속성이 추가 혹은 제거될 수도 있기에 수정을 하였으며 수정이 될 수도 있으니 두 번째 방법 또한 익혀놔야겠다
참고자료
https://www.mongodb.com/docs/realm/sdk/swift/model-data/change-an-object-model/