Computer >> 컴퓨터 >  >> 스마트폰 >> iPhone

Swift로 iOS CRUD 앱에 Realm 데이터베이스 추가하는 방법 완벽 가이드

안녕하세요! 이 글에서는 iOS 앱에 Realm 데이터베이스를 추가하는 방법을 단계별로 알아보겠습니다.

간단한 ToDo 앱을 직접 만들어 보면서 Realm 데이터베이스에서 CRUD(Create, Read, Update, Delete) 작업을 수행하는 방법을 익힐 수 있습니다.

Realm이란 무엇인가?

Swift로 iOS CRUD 앱에 Realm 데이터베이스 추가하는 방법 완벽 가이드

Realm은 개발자 친화적이고 사용하기 쉬운 오픈소스 모바일 데이터베이스입니다. iOS 앱에서 Core Data의 대안으로도 활용할 수 있습니다.

Realm은 크로스 플랫폼 모바일 데이터베이스이기 때문에 네이티브 Android 및 iOS 앱은 물론, React Native로 제작한 크로스 플랫폼 앱에서도 사용할 수 있습니다. Objective-C, Swift, Java, Kotlin, C#, JavaScript 등 다양한 언어를 지원합니다.

iOS 프로젝트에 Realm 설정하기

Realm은 SPM(Swift Package Manager), CocoaPods, Carthage 중 어떤 것을 사용해서든 프로젝트에 추가할 수 있습니다. 여기서는 가장 널리 쓰이는 CocoaPods를 이용해 Realm Pod를 추가하는 방법을 살펴보겠습니다.

  1. Xcode를 열고 Core Data를 사용하지 않는 UIKit + Swift 기반의 빈 iOS 앱 프로젝트를 생성합니다.
  2. Xcode를 닫고 터미널을 연 뒤, 프로젝트 디렉터리로 이동합니다.
  3. 다음 명령어를 실행해 Podfile을 생성합니다.
pod init

4. 디렉터리 내용을 확인해 보면 새로운 Podfile이 생성된 것을 볼 수 있습니다. 텍스트 편집기(여기서는 Vim을 사용했습니다)로 파일을 열어 아래 이미지와 같이 수정한 뒤 저장하고 닫습니다.

Swift로 iOS CRUD 앱에 Realm 데이터베이스 추가하는 방법 완벽 가이드

Realm DB 의존성을 지정했다면, 아래 명령어로 의존성을 설치합니다:

pod install 
Swift로 iOS CRUD 앱에 Realm 데이터베이스 추가하는 방법 완벽 가이드

이제 iOS 프로젝트에 Realm DB 의존성이 성공적으로 추가되었습니다. 다음 명령어를 실행해 Xcode에서 프로젝트를 엽니다.

open YOUR_APP_NAME.xcworkspace

참고: Xcode를 연 후에는 반드시 Command+B를 눌러 프로젝트를 한 번 빌드해 주세요.

사용자 인터페이스(UI) 디자인하기

앱의 UI는 최대한 심플하게 유지하겠습니다. Main.storyboard를 열고 아래 그림과 같이 프로토타입 셀이 포함된 테이블 뷰를 추가해 간단한 화면을 구성합니다. 이후 내비게이션 컨트롤러를 임베드하고, ViewController.swift 파일에 테이블 뷰의 IBOutlet을 생성합니다:

Swift로 iOS CRUD 앱에 Realm 데이터베이스 추가하는 방법 완벽 가이드

Realm에서 데이터 모델 만들기

ToDo 앱에서 각 작업(task)은 작업 이름과 작업 ID를 가집니다. 할 일을 표현하는 모델 클래스를 만들어 보겠습니다. 프로젝트 네비게이터에서 우클릭하여 새 Swift 파일을 생성하고 아래 코드를 추가합니다.

import Foundation
import RealmSwift


class ToDoTask:Object
{
    @objc dynamic var tasknote: String?
    @objc dynamic var taskid: String?
}

위 코드에서 ToDoTask라는 이름의 모델 클래스를 생성했습니다. 이 클래스는 RealmDB에서 제공하는 Object 클래스를 상속받으며, Object 클래스는 이 모델로 생성된 데이터를 데이터베이스에 저장하는 내부 처리 과정을 모두 담당합니다.

또한 두 개의 속성을 추가했습니다. 할 일 내용을 담는 tasknotetaskid이며, 둘 다 문자열 타입입니다. @objc는 해당 Swift 코드가 Objective-C에 노출됨을 의미하고, dynamic은 Objective-C의 동적 디스패치(dynamic dispatch)를 사용한다는 의미입니다.

기본 CRUD 앱 기능 구현하기

우리가 만들 앱은 다음과 같은 기능을 수행합니다:

  1. AlertViewController를 사용해 사용자로부터 입력을 받습니다.
  2. 입력값을 데이터베이스와 테이블 뷰에 추가합니다.
  3. 사용자가 입력한 내용을 수정할 수 있게 합니다.
  4. 행을 스와이프해 삭제하면 테이블 뷰와 데이터베이스 양쪽에서 데이터를 제거합니다.
  5. 앱 실행 시 데이터베이스에서 모든 데이터를 가져와(데이터가 있다면) 테이블 뷰에 표시합니다.

AlertViewController로 사용자 입력 받기

ViewController.swift 파일을 열고 ViewDidLoad() 메서드 안에 아래 코드를 추가합니다. 그리고 addTask()라는 새 함수를 만들어, 텍스트 박스가 포함된 AlertViewController를 띄워 사용자 입력을 받는 코드를 작성합니다.

이제 오른쪽 바 버튼을 누르면 addTask() 함수가 호출되어 텍스트 필드가 있는 alertviewcontroller가 표시되고, 사용자의 입력을 받을 수 있습니다.

navigationItem.rightBarButtonItem = UIBarButtonItem(image: .add, style: .done, target: self, action: #selector(addTask))

navigationController?.navigationBar.prefersLargeTitles = true

title = "RealmDB"
@objc
    func addTask()
    { 
        let ac = UIAlertController(title: "Add Note", message: nil, preferredStyle: .alert)
        
        ac.addTextField(configurationHandler: .none)
        
        ac.addAction(UIAlertAction(title: "Add", style: .default, handler: { (UIAlertAction) in
          
              if let text = ac.textFields?.first?.text
            {
                print(text)
            }
            
        }))
        ac.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        present(ac, animated: true, completion: nil)
    }

입력값을 데이터베이스와 테이블 뷰에 추가하기

Realm에 데이터를 저장하려면 먼저 Realm 인스턴스를 얻어야 합니다. 이 인스턴스를 통해 CRUD 작업에 필요한 모든 메서드에 접근할 수 있습니다. ViewController.swift 파일에 Realm 타입의 프로퍼티를 선언하고 viewDidLoad() 메서드에서 초기화합니다.

 var realmDB: Realm!
 override func viewDidLoad() {
        super.viewDidLoad()
        
        navigationItem.rightBarButtonItem = UIBarButtonItem(image: .add, style: .done, target: self, action: #selector(addTask))
        navigationController?.navigationBar.prefersLargeTitles = true
        title = "RealmDB"
        
        realmDB = try! Realm()
       
    }

그다음 데이터 모델(ToDoTask) 타입의 빈 배열을 생성합니다. 이 배열은 테이블 뷰와 데이터베이스에 추가될 모든 작업을 담게 됩니다.

이제 addTask() 함수 안에서 Add 액션 클로저를 수정하여, 사용자 입력을 받고 해당 입력에 대한 랜덤 ID를 생성하도록 합니다. 그런 다음 배열에 추가하고 데이터베이스에 저장합니다.

var tasks = [ToDoTask]()
 if let text = ac.textFields?.first?.text
            {
            	//데이터 모델 배열에 데이터 추가
                let t = ToDoTask()
                t.taskid = UUID().uuidString
                t.tasknote = text
                self.tasks.append(t)
                
                //데이터베이스에 데이터 추가
                try! self.realmDB.write {
                    self.realmDB.add(t)
                }
                //테이블 뷰 UI 갱신
                self.tasktv.reloadData()
            }

이 시점에서 앱을 실행하면 데이터가 데이터베이스에 저장됩니다. 하지만 아직 델리게이트 메서드를 구현하지 않았기 때문에 테이블 뷰에는 표시되지 않습니다.

ViewController 클래스가 UITableViewDelegateUITableViewDataSource 프로토콜을 채택하도록 하고, 프로토콜 스텁(stub)을 추가합니다.

numberOfRowsInSection 메서드 안에서는 tasks 배열의 개수를 반환합니다. 이 값이 테이블 뷰에 추가될 행의 수, 즉 tasks 배열의 요소 개수와 일치합니다.

 func tableView(_ tableView: UITableView, numberOfRowsInSection section: 
 Int) -> Int 
 {
        return tasks.count;
 }

다음으로 각 행에 표시할 내용을 지정해야 합니다. 이 작업은 cellForRowAt 델리게이트 메서드에서 수행합니다. 여기서는 스토리보드에서 지정한 식별자(identifier)로 셀을 재사용(dequeue)하고, 라벨 텍스트를 tasks 배열 요소의 tasknote 속성 값으로 설정합니다.

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
        {
            cell.textLabel?.text = tasks[indexPath.row].tasknote
            return cell
        }
        return UITableViewCell()
    }

사용자가 입력값을 수정할 수 있게 하기

이제 사용자가 입력한 작업을 수정하고, 변경 사항을 데이터베이스와 UI 양쪽에 모두 반영해야 합니다. 이는 앞서 사용자 입력을 받았던 방식과 유사한 방법으로 구현할 수 있습니다. 사용자가 테이블 뷰의 행을 탭하면 호출되는 didSelectRowAt 델리게이트 메서드를 구현합니다.

아래 코드는 텍스트 필드가 있는 AlertViewController를 표시합니다. 입력된 텍스트로 셀의 내용을 업데이트하는 동시에 데이터베이스의 내용도 함께 갱신합니다.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        let tasktomodify = tasks[indexPath.row]
        let ac = UIAlertController(title: "Update task", message: nil, preferredStyle: .alert)
        
        ac.addTextField(configurationHandler: .none)
        ac.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (UIAlertAction) in
            if let text = ac.textFields?.first?.text
            {
                if(!text.isEmpty)
                {
                try! self.realmDB.write({
                    tasktomodify.tasknote = text
                })
                self.tasktv.reloadData()
                }
            }
        }))
        
        present(ac, animated: true, completion: nil)
    }

스와이프로 행 삭제하고 테이블 뷰와 데이터베이스에서 데이터 제거하기

이번에는 테이블 뷰에 스와이프 삭제(swipe to delete) 기능을 구현해 사용자가 작업을 삭제할 수 있도록 하겠습니다. 사용자가 테이블 뷰의 행을 스와이프해서 삭제하면, 내부적으로는 데이터베이스와 데이터 모델 배열에서 해당 데이터를 삭제하고 테이블 뷰의 UI도 갱신해야 합니다.

이는 commit editingStyle 델리게이트 메서드를 구현하고 아래 코드를 추가함으로써 가능합니다:

 func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete
        {
            let tasktoDelete = tasks[indexPath.row]
            try! realmDB.write({
                realmDB.delete(tasktoDelete)
                self.tasks.remove(at: indexPath.row)
                self.tasktv.deleteRows(at: [indexPath], with: .fade)
            })
        }
    }

데이터베이스에서 모든 데이터를 가져와 테이블 뷰에 표시하기

마지막으로 Read(읽기) 작업을 구현하겠습니다. 사용자가 앱을 실행할 때마다 데이터베이스에서 데이터를 가져와(데이터가 존재하는 경우) 테이블 뷰에 표시해야 합니다.

뷰 컨트롤러 Swift 파일에 getTodo 함수를 만들고 그 안에 아래 코드를 추가하면 됩니다:

func getTodos()
    {
       //데이터베이스에서 모든 데이터 가져오기
        let notes = realmDB.objects(ToDoTask.self)
        
        //중복 방지를 위해 모델 데이터 배열 초기화
        self.tasks.removeAll()
        
        /*가져온 데이터가 비어 있지 않으면 모델 데이터 배열에 추가하고 UI 갱신 */
        if(!notes.isEmpty)
        {
        for n in notes
        {
            
            self.tasks.append(n)
            
        }
            self.tasktv.reloadData()
        }
        
        
    }

보너스 팁: iOS 시뮬레이터에서 데이터베이스 내용 확인하기

이제 앱을 실행하면 의도한 대로 작동하는 것을 확인할 수 있습니다. 그런데 데이터가 정말 데이터베이스에 저장되었는지는 어떻게 확인할 수 있을까요? MongoDB Realm Studio라는 앱을 사용하면 시뮬레이터의 Realm 데이터베이스에 저장된 데이터를 직접 확인할 수 있습니다.

참고: 이 방법은 iOS 시뮬레이터로 앱을 테스트할 때만 작동합니다.

viewDidLoad() 메서드에 아래 코드를 추가하면 앱의 실제 파일 경로가 출력됩니다:

 print(realmDB.configuration.fileURL!)
Swift로 iOS CRUD 앱에 Realm 데이터베이스 추가하는 방법 완벽 가이드

콘솔에 출력된 파일 경로를 복사한 뒤, 터미널을 열고 다음 명령어를 실행합니다:

open REALM_FILE_PATH_HERE
위 명령어를 실행하기 전에 반드시 MongoDB Realm Studio를 미리 다운로드해 두세요.

이제 앱의 RealmFile이 MongoDB Realm Studio에서 열립니다. 데이터베이스에 저장된 데이터가 테이블 형태로 표시됩니다.

작업을 수정하거나 삭제하는 등 데이터에 변경을 가하면, 그 변화가 MongoDB Realm Studio 앱에도 실시간으로 반영되는 것을 확인할 수 있습니다:

Swift로 iOS CRUD 앱에 Realm 데이터베이스 추가하는 방법 완벽 가이드

축하합니다! 이제 iOS 앱에서 CRUD 작업을 구현한 간단한 앱을 성공적으로 완성했습니다.