-
[iOS] Realm Migration🍎iOS 2022. 10. 13. 12:45
안녕하세요 Skyler입니다 :)
오늘은 마이그레이션에 대해서 배워봤습니다!
출시 프로젝트에서 제가 Realm 테이블 구조를 잘못 건드렸다가 Crash가 나는 상황이 생겨서 황급히 마이그레이션을 적용해봤는데요!
덕분에 Crash를 막아서 한시름 놓았습니다😇
혹시 저처럼 실수하신 분들은 참고하셔서 오류 해결에 도움 되셨으면 좋겠습니다!😊마이그레이션
- 새로운 테이블 추가
- 기존 테이블 - 칼럼 삭제 / 추가 / 이름 변경 / 타입 변경 등 Realm 데이터에 변화가 있을 때 출시 후에 적용해야 함
- 이전 스키마 버전과 달라지면 무조건 해야 함!
- if를 통해서 버전마다의 마이그레이션을 해줘야 함!
- Realm Schmea Version을 체크해보자!
기존 Realm 모두 삭제하고 실행
let config = Realm.Configuration(schemaVersion: 1, deleteRealmIfMigrationNeeded: true) Realm.Configuration.defaultConfiguration = config- deleteRealmIfMigrationNeeded를 사용하면 기존 렘을 삭제하기 때문에 디버그 시에는 사용해도 되지만 실제 릴리즈시에는 반드시 제거해줘야 함! 제거하지 않으면 사용자들의 렘 데이터가 모두 삭제돼버림..
- 위에서 schemaVersion은 항상 최신 버전으로 갱신해줘야 함
- 렘의 테이블 구조를 변경했다가 다시 원래로 돌려줘도 schemaVersion이 달라지기 때문에 마이그레이션이 필요함
- schemaVersion은 0으로 했다가 100 입력하게 되면 그 사이에 있는 버전 1~99는 사용을 못하게 됨
- schemaVersion은 마이그레이션을 진행한 횟수와 같음(따로 값을 지정해주지 않는다면!)
- 위의 코드를 사용하면 디버그 모드 실행 시 테이블 구조가 변경되어도 앱을 삭제하고 재실행하지 않아도 됨!
스키마 버전에 대한 분기 처리
let config = Realm.Configuration(schemaVersion: 2) { migration, oldSchemaVersion in if oldSchemaVersion < 1 { } if oldSchemaVersion < 2 { } }- 현재 나의 스키마 버전이 0이라면 1보다 작은 조건을 수행하고 2가 되지 않았기 때문에 또 2보다 작은 조건에 대해 수행함
- else if를 사용하지 않는 이유는 각각의 스키마 버전마다 다 체크를 하고 넘어가야 하기 때문에 if를 사용함
- Realm의 초기화 구문의 매개변수 명을 변경하는 것은 상관없음!
Realm 컬럼 이름 변경 시 사용
migration.renameProperty(onType: Todo.className(), from: "favorite", to: "importance")- 만약 Realm 컬럼의 이름을 바꾼다면 위 코드와 같이 기존의 이름과 바뀐 이름을 명시해주면 됨!
Realm 데이터 추가 삭제 및 초기값 설정
migration.enumerateObjects(ofType: Todo.className()) { oldObject, newObject in guard let new = newObject else { return } guard let old = oldObject else { return } new["userDescription"] = "안녕하세요 \\(old["title"]!)의 중요도는 \\(old["importance"]!)입니다" }- 컬럼 단순 추가 삭제의 경우에는 별도 코드가 필요 없음
- 단, 데이터가 없는 초기값을 설정해야 한다면 위처럼 따로 설정해줘야 함!
- newObject에는 새로 추가된 데이터 oldObject에는 기존에 있었던 데이터 값들을 통상적으로 사용
- 만약 컬럼 단순 추가 삭제의 경우에 별도 코드가 없을 경우 추후에 보았을 때 그때 정확하게 어떤 변화가 있었는지에 대해서 알기 어렵기 때문에 주석과 그때그때의 커밋을 해서 기록해서 관리를 하는 것이 좋음
Realm 컬럼의 타입 변경 시 사용
migration.enumerateObjects(ofType: Todo.className()) { oldObject, newObject in guard let new = newObject else { return } guard let old = oldObject else { return } new["importance"] = old["importance"] ?? 4.4 if old["importance"] < 4 { new["importance"] = 5.5 } }- 타입이 만약 기본 타입에서 옵셔널로 변경되어도 타입 변경에 대한 마이그레이션을 해줘야 함!
- 타입 변경은 위처럼 기존의 컬럼을 새로운 컬럼에 할당하는 식으로 넣어주면 됨
- 그리고 타입 변경 시에는 기존의 값들에 대한 처리도 위처럼 if 문으로 처리를 해줘야 함!
- 만약 기존의 타입이 옵셔널이고 새로운 타입이 옵셔널이 아니라면 위처럼 nil에 대한 값 처리는 해줘야 함
Realm의 테이블마다의 분기 처리 방법
migration.renameProperty(onType: Todo.className(), from: "favorite", to: "importance") migration.enumerateObjects(ofType: Todo.className())- 테이블이 여러 개라면 위의 onType이나 ofType에서 테이블 명에 명시해주고 해당 테이블에 대한 마이그레이션만 적용해주면 됨!
Realm에 새로 설정한 Configuration 할당
Realm.Configuration.defaultConfiguration = config- 위에서 스키마의 버전 별로 마이그레이션 처리해준 Realm의 Configuration을 나의 Realm에 할당해주는 작업이라고 생각하면 됨!
'🍎iOS' 카테고리의 다른 글
[iOS] Realm List, EmbededObject (0) 2022.10.23 [iOS] Firebase, Push Notification, Messaging (0) 2022.10.23 [iOS] Margin, 데이터베이스 (0) 2022.08.22 [iOS] UIView, NotificationCenter (0) 2022.08.19 [iOS] TypeCasting (0) 2022.08.18