일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- swift database
- SeSAC
- ribs
- Subscribe
- Swift Tuist
- ios swiftdata
- RxSwift
- Subject
- swift db
- Firebase
- swiftdata
- observable
- GCD
- Combine
- ios
- Firebase Analytics
- Tuist Swift
- swift 5.9
- KeyPath
- swift 6
- swift
- Tuist
- ios database
- arc
- 카카오뱅크 ios
- JSON
- realm
- 네트워크 통신
- xcode
- SwiftUI
- Today
- Total
천원의 개발
iOS Realm Migration(마이그레이션) 하는 법 본문
마이그레이션?
- Realm 데이터베이스를 사용하여 개발하다 보면 데이터베이스의 스키마 구조를 변경해야 할 경우가 생기는데 이런 경우 앱 충돌이 발생합니다. 개발 시에는 앱을 새로 삭제 후 실행해 주면 문제없이 작동하지만, 앱을 출시한 상태에서 스키마 구조를 변경하고 싶을 때 사용하는 게 마이그레이션 입니다.
Schema Version
- 마이그레이션을 관리 하기 위한 스키마 버전입니다. 처음 상태는 0으로 시작합니다.
- 컬럼의 추가나 삭제 같은 동작은 Schema Version을 증가 시 키는 것만으로 마이그레이션이 이루어집니다.
스키마 버전을 출력해주는 코드입니다.
do {
let version = try schemaVersionAtURL(fileURL!)
print("Schema Version: \(version)") // Schema Version: 0
} catch {
print(error)
}
컬럼 추가하기
현재 데이터베이스의 스키마입니다.
class User: Object {
@Persisted var name: String
@Persisted var address: String
@Persisted var age: Int
@Persisted(primaryKey: true) var objectId: ObjectId
convenience init(name: String, address: String, age: Int) {
self.init()
self.name = name
self.address = address
self.age = age
}
}
여기에 phoneNumber를 컬럼에 추가 해줍니다.
class User: Object {
@Persisted var name: String
@Persisted var address: String
@Persisted var age: Int
@Persisted var phoneNumber: Int
@Persisted(primaryKey: true) var objectId: ObjectId
convenience init(name: String, address: String, age: Int) {
self.init()
self.name = name
self.address = address
self.age = age
}
}
그런 후 AppDelegate의 didFinishLaunchingWithOptions에서 아래 코드를 실행해 줍니다.
단순히 컬럼을 추가 해주는 동작은 schemaVersion을 하나 올려 주기만 해도 이루어집니다.
let config = Realm.Configuration(schemaVersion: 1) // schemaVersion을 1로 올림
Realm.Configuration.defaultConfiguration = config
phone 컬럼이 추가된 모습입니다.
하지만 위에 코드를 사용하면 직관적이지 못하기 때문에 migrationBlock
을 활용해 줍시다.
여기서 if 문을 통해서 schemaVersion 0 > schemaVersion 1 로 갈 때 동작을 수행할 수 있지만 단순히 컬럼을 추가해주었기 때문에 아무런 동작을 하지 않아도 됩니다.
let config = Realm.Configuration(schemaVersion: 1) { migration, oldSchemaVersion in
if oldSchemaVersion < 1 { // version 0 > 1 phoneNumber 컬럼 추가
}
} // schemaVersion을 1로 올림
Realm.Configuration.defaultConfiguration = config
삭제 또한 같은 방식으로 해주면 됩니다.
프로퍼티명 변경 하기
User 스키마에서 address -> location 으로 프로퍼티명을 변경 하고싶다면 renameProperty 메서드를 사용해서 변경 할 수 있습니다.
먼저 스키마를 변경 해줍니다.
class User: Object {
@Persisted var name: String
@Persisted var location: String // 변경
@Persisted var age: Int
@Persisted var phoneNumber: Int
@Persisted(primaryKey: true) var objectId: ObjectId
convenience init(name: String, address: String, age: Int) {
self.init()
self.name = name
self.location = address
self.age = age
}
}
schemaVersion -> 2로 올려줍니다.
renameProperty를 활용하여 프로퍼티명을 변경 해줍니다.
let config = Realm.Configuration(schemaVersion: 2) { migration, oldSchemaVersion in
if oldSchemaVersion < 1 { // version 0 > 1 phoneNumber 컬럼 추가
}
if oldSchemaVersion < 2 { // version 1 > 2 address -> location 프로퍼티명 변경
migration.renameProperty(onType: User.className(), from: "address", to: "location")
}
}
Realm.Configuration.defaultConfiguration = config
location으로 변경된 모습
Linear Migrations
- 마이그레이션시에 schemaVersion의 업데이트를 순서대로 적용해야 합니다. 예를 들면 schemaVersion 0을 사용하는 사용자가 앱을 업데이트하게 되면 schemaVersion 0 > 1 phoneNumber 컬럼을 추가하는 과정과 schemaVersion 1 > 2 location 으로 프로티명을 변경 하는 과정을 모두 거쳐야 하는 것입니다. 그래서 우리는 else if 문을 사용하는 것이 아닌 if 문을 중첩 사용하여 Linear 형태로 Migration 해줍니다.
컬럼 생성 시 초깃값
컬럼에 초기값을 포함하여 추가를 해보겠습니다.
먼저 테이블을 변경 해줍니다.
class User: Object {
@Persisted var name: String
@Persisted var location: String
@Persisted var age: Int
@Persisted var phoneNumber: Int
@Persisted var introduce: String // 초기값 포함하여 추가
@Persisted(primaryKey: true) var objectId: ObjectId
convenience init(name: String, address: String, age: Int) {
self.init()
self.name = name
self.location = address
self.age = age
}
}
가장 먼저 스키마 버전을 3으로 올려줍니다.
enumerateObjects 메서드를 활용하여 초깃값을 부여해줍니다.
let config = Realm.Configuration(schemaVersion: 3) { migration, oldSchemaVersion in
if oldSchemaVersion < 1 { // version 0 > 1 phoneNumber 컬럼 추가
}
if oldSchemaVersion < 2 { // version 1 > 2 address -> location 프로퍼티명 변경
migration.renameProperty(onType: User.className(), from: "address", to: "location")
}
if oldSchemaVersion < 3 { // version 2 > 3 introduce 컬럼 생성 및 초기값 부여
migration.enumerateObjects(ofType: User.className()) { oldObject, newObject in
guard let new = newObject else {return}
guard let old = oldObject else {return}
new["introduce"] = "안녕하세요 \(old["name"]!)입니다. \(old["location"]!)에서 왔습니다."
}
}
}
Realm.Configuration.defaultConfiguration = config
introduce가 정상적으로 추가 된 모습입니다.
마이그레이션은 코드가 지저분하고 한번 사용하면 변경하지 못하기 때문에 처음 스키마를 설계 시에 신중하게 하고 마이그레이션을 하게 되더라도 최소화하는 방향으로 개발하는 것이 좋습니다.
여기까지 Realm Migration 정리였습니다.
출처:
🌱SeSAC iOS 2기 69회차 강의자료
'iOS&Swift🍎 > iOS' 카테고리의 다른 글
iOS Result 타입을 활용한 에러처리 (0) | 2022.11.01 |
---|---|
iOS URLSession 정리 (0) | 2022.10.17 |
iOS Codable 사용법 (0) | 2022.10.13 |
iOS Firebase Cloud Messaging Service를 이용하여 Remote/Push Notification 사용하기 (0) | 2022.10.12 |
iOS Firebase Crashlytics 사용법 (0) | 2022.10.11 |