[ DataBase ] 내가 선택한 Realm 의 성능?

2024. 2. 17. 05:06Mobile/iOS libraries

Build better apps, faster.

( 최상의 앱을 빠르게 구축해보세요!)

realm signature logo

 

(⚠️ 유의: 이 글은 Realm 뒷광고가 아닙니다..😅)

 

 

안녕하세요. 이번 글에선 말투를 좀 달리해서 대화체로 해볼까 해요. 주로 혼자 독백체로 학습, 회고, 경험한 글을 썼는데요. 

누군가에게 친근하게 다가갈 수 있지 않을까 해서 어투를 바꿔봤습니다.

 

저는 Realm 을 3년 전 부터 들어왔어요. 더불어 CoreData 도요..그런데 적용해볼 생각을 안했던 것 같아요. 

SwiftData 가 나온 마당에 웬 CoreData에 Realm 이냐고요..? 


  Realm 을 선택한 이유  

이번 글은 제 개인 프로젝트에서 적용하기 위한 라이브러리로 제가 Realm 을 선택하게 되었기에, 학습해보고 어떻게 코드를 적용하는지에 대한 간단한 정리와 수기 글이 될 것 같아요.  사실 트렌드를 따라가보고 싶은 욕심도 있지만, 천리길도 한 걸음부터라고 안해본 것이니 해보고 싶었던 것도 있었거든요.

 

(여담: 작년 하반기부터 개인 앱을 만들고 있다보니, os 나 Xcode 버전이 아직 바로 그 아래이기도 합니다. 4월엔 애플에서 Xcode 15, iOS 17 이상을 강제하고 있기때문에, 기존 버전으로 출시하고,  그 후 업데이트 때 버전 업하려고해요. )

 

글을 쓰기 전에 CoreData 로도 데이터 가지고 오는것을 해보고 Realm으로도 데이터를 가지고 와봤어요.

저는 녹음과 연관된 어플을 만들고 있거든요.  개인적인 것을 녹음하고 저장하기에 서버를 외부로 빼서 어디서든 사용하는 느낌보다는 개인적인 나만의 저장소 같은 느낌을 주고 싶어서 사용자의 개인 기기에 저장하도록 Local DB로 관리하고 싶었어요. 

  Realm 의 강점과 히스토리   

Realm(relm, 뤪🙄)은 CoreData(코어데이터) 와 다른 강점이 있어요.  안드로이드와도 데이터를 공유할 수 있다는 점인 것 같아요. 뿐만 아니라 크로스 플랫폼인 Xamarin(MS), React Native(Facebook a.k.a. meta) 등에서도 사용할 수 있대요. 

Realm 은 2019년에 MongoDB 에 병합되었네요. MongoDB 하면 NoSQL 이 먼저 생각이 나요. 

아무래도 저는 백엔드가 아닌 클라이언트단 프론트엔드 개발자다보니 전통적인 RDBMS 가 아닌 NoSQL 베이스인 것들이 부담이 없더라고요.  예전에 했던 프로젝트에서는 파이썬 기반의 Django 로 CRUD 를 구축하고 DB 응답값과 요청값을 설정했던 경험도 있었고요. 

 

 Realm 의 강점을 몇가지로 요약해보자면 아래와 같을 거에요.

  • 실시간 업데이트 및 동기화: 데이터 변경을 즉시 감지해 관련된 모든 구독자에게 실시간 업데이트를 제공.
    →  실시간으로 변하는 데이터를 효율적으로 처리하고 화면에 반영하는데 유용 
    이 부분은 Realm 이 MVCC(Multiversion concurrency control,다중버전 동시성제어) 과 동시성을 처리하기에 가능한 것이죠. 

  • 간편한 사용 및 통합 Realm 은 객체 지향 프로그래밍에 중점을 두고, 데이터를 객체로 직접 매핑한다.
    →  개발자가 데이터를 객체로 다루기 쉽게 만들어주며, 데이터베이스 작업을 일반적인 객체 지향 프로그래밍과 통합하기 용이하다. 
  •  성능 : 뛰어난 성능 제공 
    •  내장된 C++ 코어: 모바일 기기에서도 부드러운 데이터베이스 액세스 및 쿼리 실행 가능 
    • Zero-Copy 아키텍쳐: 데이터를 디스크에서 메모리로 직접 로드하고 저장. 데이터베이스 액세스 시 복사를 최소화하고 빠른 속도를 제공  등이 있음.

              →  모바일에서 사용시 가볍고 메모리, 디스크 공간, 배터리 수명 등 효율적으로 사용할 수 있다. 

  • 다양한 프로그래밍 언어 지원: Objective-C, Swift, JAVA(android), C#, Javascript, C++ 

데이터베이스 측면

  • 효율적인 쿼리 및 검색: Realm은 쿼리 작성이 간편하며, 복잡한 데이터 구조에서도 효과적으로 검색할 수 있는 기능을 제공
  • 객체 지향 스키마 정의: Realm에서는 객체가 데이터베이스의 스키마(데이터의 구조)를 정의하므로, 스키마 변경이 코드 변경과 밀접하게 연결되어 있다. 이로써 스키마 변경에 따른 번거로움을 줄일 수 있음. 
    →   개발자에게 직관적: Realm의 객체 지향 데이터 모델은 배우기 쉽고 ORM이 필요하지 않으며 코드 작성을 줄일 수 있다.
  • 오프라인을 위한 설계: Realm 의 로컬 데이터베이스는 데이터를 기기의 디스크에 유지하므로 앱은 온라인에서 마찬가지로 오프라인에서도 잘 작동한다.

 

NOTE: 스키마(schema)
데이터베이스 테이블이나 객체의 필드, 타입, 제약 조건 등에 대한 전반적인 설계를 의미

 


  Swift 에서의 사용법   

( 2024년 2월 기준, 사용한 Realm 버전은 10.47.0, SPM 으로 설치했음)

Model Data  - 객체 모델 정의

// 정규 Swift 클래스처럼 모델을 정의할 수 있다!
class Picture: Object {
    @Persisted var name1: String
    @Persisted var age: Int
}

class Owner: Object {
    @Persisted(primaryKey: true) var _id: String
    @Persisted var name: String
    @Persisted var age: Int
    // 다른 객체 필드와 relationships 형성
    @Persisted var pictures: List<Picture>
}

객체 지향: 코드 간소화 가 됩니다. 

Persist - 지속성 있는 이라는 뜻이에요. 데이터베이스의 필드 타입 지정후 그 형태로 데이터들 저장하고 관리할 수 있어요. 클래스명은 Realm 테이블 이름이 돼요. 클래스 프로퍼티(속성) 은 로컬 DB 에 유지가 됩니다. Owner 라는 클래스는 프라이머리 키가 있어요. 기준이 되어주는 녀석이죠. 

 

📌 NOTE
예전에 모델을 정의했을 때는 @objc dynamic 을 붙이거나 클래스에 @objc member class 를 붙이고 dynamic 만 붙였어요.
지금은 @Persisted 라는 구조체 타입의 프로퍼티래퍼(@propertyWrapper) 로 붙여주면 됩니다.
 @objc dynamic 을 써줘도 되나봐요. 이건 문서를 더 찾아보면 나올 것 같기도 하고요. 

 

아래가 예전에 데이터모델을 정의해줬을 때 붙는 프로퍼티 래퍼

import Foundation
import RealmSwift 

class Data: Object {
    @objc dynamic var name: String = ""
    @objc dynamic var email: String? = nil
    
    convenience init(name: String, email: String?) {
        self.init()
        self.name = name
        self.email = email
    }
}

Realm File 관리

기본 realm 세팅 또는 file url 열기

// Open the default realm
let defaultRealm = try! Realm()

// Open the realm with a specific file URL, for example a username
let username = "GordonCole"
var config = Realm.Configuration.defaultConfiguration
config.fileURL!.deleteLastPathComponent()
config.fileURL!.appendPathComponent(username)
config.fileURL!.appendPathExtension("realm")
let realm = try! Realm(configuration: config)

 

데이터 값 추가

private func realmAdd(data: TodoThingsData) {
  do {
      try realm.write {
          realm.add(data)
      }
  } catch {
      print("Error saving data \(error)")
  }
}

.write 클로저 안에 realm 인스턴스에 .add 메소드 그리고 전달인자로 data (TodoThingsData 클래스의 속성값들을)  추가해줘요. 

데이터 수정(업데이트)

업데이트 수정도 이 write 블록 내에서 해결이 됩니다!

테이블 셀 내에서 변경하고, 그 변경한 값을 업데이트 해서,

 

do {
    try self.realm.write {
        self.itemArray?[cellAtRow].category = self.selectedCategory.rawValue
        self.itemArray?[cellAtRow].isChecked = self.itemArray?[cellAtRow].isChecked ?? false
        
        self.itemArray?[cellAtRow].name = safeTitleTextFieldValue
    }
} catch {
    print("Error edit item: \(error)")
}


self.tableView.reloadData()

바꿔주고, 테이블뷰의 수정한 업데이트 내용을 다시 로드해주는 .reloadData() 메소드를 적용해줍니다.

데이터 삭제

do {
    try self.realm.write {
        self.realm.delete(cellData)
    }
} catch {
    print("Error delete data: \(error)")
}

self.tableView.reloadData()

삭제는 realm 안에 데이터에 .delete 메소드 안 테이블뷰셀 데이터 → cellData 를 넣어줬어요.

테이블뷰의 데이터 값은 동일하게 reloadData 를 해주고요.

 

Realm 데이터베이스 세팅 후,  데이터가 저장된 데이터 테이블 값 확인

Realm Studio 를 다운받아서 확인할 수 있어요. 
( 필요하신 분들은 이 링크 를 눌러주세요.)

File Path(파일 경로) 를 설정해주고 그 방법은 

// Get on-disk location of the default Realm
let realm = try! Realm()
print("Realm is located at:", realm.configuration.fileURL!)

 

debugging 되는 출력값은 

Realm is located at: file:///Users/Library/Developer/CoreSimulator/Devices/7E40169F-6ED9-4E06-8135-E6A9D8C1DF2A/data/Containers/Data/Application/F8E5B65A-8F1C-4A15-9372-1BCF88A726BE/Documents/

 

 

값을 create(post) 해주면 디버깅 창에 이렇게 파일 경로가 뜨고 finder 에서 이 경로로 이동하면 realm 파일로 이동하고 이걸 realmStudio 로 열면 데이터 테이블을 확인할 수 있어요.

 

 

셀을 삭제해봤어요

 

좌측 - 삭제 전 데이터 테이블
왼쪽 - 데이터테이블 내 데이터 삭제 전, 오른쪽 - 데이터 삭제 후 적용

 

 

그 후에 데이터도 삭제된 걸 보실수 있어요.

 

추가로 제가 Realm 데이터 클래스의 이름을 변경했는데, 그 아래 변경된 걸로 다시 추가가 된 것을 볼 수 있었어요. 

 

 

생각보다 Realm 이 지원하고 관리해주는 성능적인 부분들이 많았어요. 앞서 언급한 동시성 부분과 연관된 코드와 문서가 정말 길더라고요. 

동시성부분은 저도 꾸준히 공부하려고 해서 다음에 동시성 중 actor 나 async await 를 다룰 때 다뤄봐야겠어요. 내용이 꽤 길어질 것 같거든요 ^^;;  그 외에 테스트 코드, 검색  등등.. 아무래도 네이티브 모바일 환경 뿐만 아니라 웹, 다른 크로스플랫폼 등까지 쓰여서 문서 양이 정말 방대하더라고요. 찬찬히 읽어보면 도움이 될 것 같아요. 

 

 

참고자료

 

공식 문서 :  Realm Swift SDK 문서 by MongoDB                  

                    Realm Swift 최신 문서 (ver 10.47.0  - 2024.02 기준)

ChatGPT

blog link: data persistence in swift with realm

(예시코드를 참조한 블로그 글입니다. 문제시 글을 남겨주세요.

This is a medium post where I referenced the example code. Please comment if you have any issues. and I will edit or remove the codes and images. Thanks. ) 

 

설치방식: cocoapod / Swift Package Manager

https://github.com/realm/realm-swift

 


잘못된 정보나 오타, 그 외 기타 피드백 모두 환영입니다!