본문 바로가기

IOS

Swift - Realm 통한 데이터 저장을 해보자

iOS, Android 내에서 사용가능한 내부 모바일전용 데이터베이스 이며

기존에서 사용중인 SQLite 보다 속도가 빠르며 많은 기업에서도 사용중인 내부 데이터베이스 기술이다.

 

1. Realm 라이브러리 설치 

pod 'RealmSwift'

* Realm 라이브러리 설치중 pod install 까지 완료 했으나 적용에 문제가 있을경우

다음 명령어를 이용해 리셋후 재 설치가 가능하다.

pod cache clean Realm
pod cache clean RealmSwift
pod deintegrate || rm -rf Pods
pod install --verbose

2. 데이터 클래스 생성 (User)

import Foundation
import RealmSwift

class User: Object
{
    @objc dynamic var id: Int = 0
    @objc dynamic var name: String = ""
    @objc dynamic var age: Int = 0
    let infos = List<Info>()
    
    convenience init(id:Int, name:String, age: Int) {
        self.init()
        self.id = id
        self.name = name
        self.age = age
    }
    
    override class func primaryKey() -> String? {
        return "id"
    }
}

 * 클래스 내에 override 하여 pk 값을 지정 할수가 있다.


3. 배열 데이터 클래스 생성 (User -> Info)

import Foundation
import RealmSwift

class Info: Object
{
    @objc dynamic var major: String = ""
    @objc dynamic var hobby: String = ""
    
    convenience init(major:String, hobby: String) {
        self.init()
        self.major = major
        self.hobby = hobby
    }
}

4. 데이터 저장 (ViewController)

@IBAction func SaveRealm(_ sender: UIButton)
{
  let relam = try! Realm()

  let infos1 = Info(major: "developer", hobby: "soccer")
  let infos2 = Info(major: "progamer", hobby: "lol")

  let user1 = User(id: 0, name: "철수", age: 23)
  let user2 = User(id: 1, name: "영희", age: 30)
  user1.infos.append(infos1)
  user2.infos.append(infos2)

  let user3 = User(id: 2, name: "짱구", age: 5)

  try! relam.write {
  	relam.add([user1, user2, user3])
  }
}

5. 데이터 불러오기 (ViewController)

override func viewDidLoad() 
{
  super.viewDidLoad()

  do 
  {
  	let realm = try! Realm()
  	try realm.write {
  	let users = realm.objects(User.self)
  	// 쿼리 실행후 -> 파싱하여 사용
  	}
  } catch {
  	print(error)
  }
}
쿼리 :Results<User> <0x7fcedcc14550> (
	[0] User {
		id = 0;
		name = 철수;
		age = 23;
		infos = List<Info> <0x600000a00b40> (
		
		);
	},
	[1] User {
		id = 1;
		name = 영희;
		age = 30;
		infos = List<Info> <0x600000a00c00> (
			[0] Info {
				major = developer;
				hobby = soccer;
			},
			[1] Info {
				major = progamer;
				hobby = lol;
			}
		);
	},
	[2] User {
		id = 2;
		name = 짱구;
		age = 5;
		infos = List<Info> <0x600000a00cc0> (
		
		);
	}
)
  
print("값 1 : \(realm.objects(User.self).filter("name == '영희'").first)")
   - 값 1 : User 테이블에서 name이 영희 인 값을 가져오는데 중복값이 있을경우 첫번째 값만 가져온다.

let a = realm.objects(User.self).filter("name == [c] 'USER1'")

   - 값 2 : User 테이블에서 name이 USER1 인 값을 가져오지만 대소문자 구분을 하지 않는다.

                 중복값을 가져올경우 여러 리스트를 가져올수 있다 (id 및 날짜를 통한 정렬 필요)

                 해당 값은 배열 값을 가지고 있기에 배열 주소지를 선택해서 값을 가져올수 있다 (a[0].infos)

print("값 3 : \(realm.objects(User.self).filter("id IN {1,2}"))")
  - 값 3 : User 테이블에서 id이 1 값과 2인 값을 가져온다.        

print("값 4 : \(realm.objects(User.self).filter("name BEGINSWITH 'u'"))")
  - 값 4 : User 테이블에서 name이 u로 시작하는 값을 가져온다.
  
print("값 5 : \(realm.objects(User.self).filter("name CONTAINS 'er'"))")
  - 값 5 : User 테이블에서 name에 'er'이 포함된 값을 가져온다.
  
print("값 6 : \( realm.objects(User.self) .filter("name CONTAINS '짱구'").sorted(byKeyPath: "id"))")
  - 값 6 : User 테이블에서 name에 '짱구'이 포함된 값에 대해 id 순으로 정렬한 값을 가져온다.

6. 데이터 삭제하기 (ViewController)

do
{
	let realm = try! Realm()
	try realm.write {
		let data = realm.objects(User.self).filter("name == '짱구'").first //조건부 삭제
        let data = realm.objects(User.self) // 전체삭제
		realm.delete(data!)
	}
} catch {
	print(error)
}

7. 데이터 확인하기 (Realm Studio)

   7-1 해당 Url 접속하여 운영체제에 맞게 설치 진행 -> docs.realm.io/sync/realm-studio

 

Realm Studio

 

docs.realm.io

    7-2 . URL 정보 가져오기 (Realm 주소값) 

let fileURL = Realm.Configuration.defaultConfiguration.fileURL
print(fileURL)

     * 해당 값을 출력한다 (앱을 삭제한후 재 설치할경우 해당 값이 변경 될수 있다)

     7-3. 터미널 실행후 해당 출력한 URL 정보 입력

      7-4. default.realm 를 클릭후 저장한 내용을 볼수 있다.


8. 데이터 마이그레이션

Realm 사용중에 기존 데이터 테이블의 컬럼 추가 와 같은 수정사항이 발생하게 되면 다음과 같은 오류 메세지를 띄우고 앱이 죽어버린다.

해당 내용 에대해 마이그레이션을 진행한다.

* 해당 Migration 는 최초에 1회만 적용 시키면 그 이후로는 잘 동작한다.

   8-1. 컬럼 추가

import Foundation
import RealmSwift

class User: Object
{
    @objc dynamic var id: Int = 0
    @objc dynamic var name: String = ""
    @objc dynamic var age: Int = 0
    @objc dynamic var number: Int = 0 // 추가할 컬럼
    let infos = List<Info>()
    
    convenience init(id:Int, name:String, age: Int, number:Int) {
        self.init()
        self.id = id
        self.name = name
        self.age = age
        self.number = number // 추가할 컬럼
    }
    
    override class func primaryKey() -> String? {
        return "id"
    }
}

     8-2. Appdelegate Migration

       * schemaVersion : 새로운 스키마 버전 셋팅 → 이값은 이전에 사용했던 버전보다 커야 합니다. (변동 사항 있을때 +1)

       * AppDelegate 생성시 application function 는 만들어져 있는 상태이기 때문에 안에 config 내용만 추가한다

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        let config = Realm.Configuration (
                     
            // 중요! 스키마버전 셋팅
            // 이전 버전보다 반드시 커야함
            schemaVersion: 2,

            migrationBlock: { migration, oldSchemaVersion in
                 
                // 셋팅한 스키마 버전보다 낮을경우 해당 코드 호출
                if (oldSchemaVersion < 1) {
                     
                    // 신규 업데이트 내용 추가
                    migration.enumerateObjects(ofType: User.className()) { // 추가할 컬럼 클래스
                        oldObject, newObject in
                        newObject!["number"] = Int() // 추가한 컬럼값 = 자료형()
                    }
                }
            })
         
        Realm.Configuration.defaultConfiguration = config
        
        return true
    }

  참고 : https://realm.io/kr/docs/swift/latest/#importing-the-realm-framework

https://jintaewoo.tistory.com/45

https://aircook.tistory.com/entry/Migration-in-Realm