일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 |
- 2018 KAKAO BLIND RECRUITMENT
- JSON
- CustomCode
- programmers
- 위클리챌린지
- swift
- 정보처리기사 실기 요약본
- Codable
- ios외부카메라연결
- 외부카메라감지
- cocoapods
- Xcode
- 프로그래머스
- ios카메라유선연결
- avcapturesession
- 카메라유선연결
- JSONParser
- AVFoundation
- UITableView
- Decodable
- Pod
- ios외부디바이스연결
- parse
- ios캡처감지
- usb카메라연결
- 정보처리기사 실기
- ios캡처방지
- 정보처리기사
- cancelstouchesinview
- IOS
- Today
- Total
iOS 개발일기
[iOS] Realm 사용법 본문
Realm 이란
모바일 환경에 특화되어 있고 No-SQL이며 디스크에 JSON 형태로 데이터를 저장하여 처리속도가 빠르다는 장점이 있다.
Realm을 선택한 이유
현재까지 iOS 내에서 Realm, SQLite, FMDB와 같은 데이터베이스를 사용해 보았다. ( + CoreData )
(초기에는 FMDB를 이용해서 데이터베이스를 관리했었는데 SQLite를 Swift 환경에서 사용하기 쉽도록 만들어진 라이브러리라 그런지 기본 원리는 같아도 확실히 편의성에서는 SQLite보다 FMDB가 훨씬 좋았습니다.)
Realm은 비교적 최근에 사용하였는데, 이번 새로운 프로젝트에 내부 데이터베이스에서 대용량 데이터 관리가 필요하여 빠른 처리 속도를 보장(모바일에 특화된 No-SQL 데이터베이스이기 때문)할 수 있는 Realm을 선택하게 되었다.
주관적으로는 일단 참고할 문서나 자료가 다른 내부 데이터베이스들에 많아서 학습하기 편리하다는 점과 Codable을 사용해서 데이터 변환에도 수월하다고 생각된다.
Realm 사용법
기본적인 사용법들에 대해서는 공식 홈페이지를 참고하였습니다.
Swift용 Atlas Device SDK - Atlas Device SDK
Swift SDK는 SwiftUI로 더 쉽게 작업할 수 있도록 설계된 속성 래퍼 및 편의 기능을 제공합니다. 예를 들어 일반적인 SwiftUI 패턴을 보여주는 코드 보기는 SwiftUI 문서를 확인하세요. SwiftUI 속성 래퍼가
www.mongodb.com
Entity
class Person: Object {
//기본키 지정
@Persisted(primaryKey: true)
var id: String = UUID().uuidString
@Persisted var name: String = ""
@Persisted var age: Int = 0
override init() {
super.init()
}
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
복합키를 사용하고 싶다면?
복합키로 사용하고자 하는 값들을 하나의 변수를 만들어서 조합해서 사용할 수 있다.
class Person: Object {
@Persisted(primaryKey: true)
var compoundKey: String
@Persisted var id: String = UUID().uuidString
@Persisted var name: String
@Persisted var age: String
override init() {
super.init()
}
init(name: String, age: Int) {
self.compoundKey = "\(id)_\(name)"
self.name = name
self.age = age
}
}
옵저버
옵저버를 이용하여 UICollectionView 또는 UITableView 에서 쉽게 데이터를 갱신할 수 있다.
import UIKit
import RealmSwift
class ViewController: UIViewController {
var people: Results<Person>! {
return try! Realm().objects(Persion.self)
}
var notificationToken: NotificationToken?
var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
setupNotification()
}
deinit {
notificationToken?.invalidate()
}
private func setupNotification() {
notificationToken = people.observe { [weak self] changes in
guard let tableView = self?.tableView else {return}
switch changes {
case .initial:
tableView.reloadData()
case .update(let resulsts, let deletions, let insertions, let modifications):
tableView.performBatchUpdates {
tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) }, with: .automatic)
}
case .error(let error):
print(error.localizedDescription)
}
}
}
}
CRUD
기본적으로 Realm CRUD는 반드시 쓰기 트랜잭션(write transaction) Block 내에서 실행되어야 한다.
//데이터베이스에 접근하기 위해 객체 생성
let realm = try! Realm()
//객체 생성
let person = Person(name: "hoon", age: 20)
//데이터베이스에 추가
try! realm.write {
realm.add(person)
}
//모든 객체 읽기
let persons = realm.objects(Person.self)
//정렬
let sorted = realm.objects(Person.self).sorted(byKeyPath: "name", ascending: false)
//조건을 통한 필터
let hoon = realm.objects(Person.self).where { $0.name == "hoon" }.first
//또는
let hoon = realm.objects(Person.self).where { $0.name.equals("hoon") }.first
//갱신
let person = persons[0]
try! realm.wirte {
//트랜잭션 내에서 변경하지 않을 경우 에러 발생
person.age = 24
}
//또는
try! realm.write {
let newPerson = Person(name: "hoon", age: 25)
//기본키를 조회하여 객체가 존재할 경우 업데이트
realm.add(newPerson, update: .modified)
}
//삭제
let delete = persons[0]
try! realm.write {
realm.delete(delete)
}
Realm 사용 시 주의 사항
적어도 Swift를 사용하는 사람들이라면 스레드를 직접 생성하여 사용하기보다는 DispatchQueue를 사용할 것이다.
문제는 여기서 발생한다. (메인 큐 제외)
DispatchQueue는 여러 스레드를 효율적으로 관리하기는 좋으나 Realm은 내부적으로 스레드 안전성을 보장하지 않기 때문에, 하나의 스레드에서만 Realm 인스턴스를 사용하도록 강제해야 한다. 물론, 인스턴스 뿐만 아니라 엔티티(Entity)도 마찬가지이기 때문에 스레드에 관리에 대해 주의를 기울어야 한다. DispatchQueue는 시스템에서 스레드를 관리해주기 때문에 메인 외에 다른 큐에서 실행하게되면 하나의 스레드에서 실행된다는 보장이 없다.
(`RLMException` 에러가 발생하는 이유 중 하나가 Realm 인스턴스나 엔티티에 접근하는 스레드가 다르기 때문에 발생한다.)
보통 스레드 안정성을 보장하기 위해서 메인 큐에서 Realm을 제어하는 경우가 많다.
(메인 큐에 존재하는 스레드는 메인 스레드 하나이기 때문이다.)
예를 들어, 위 옵저버를 이용해서 UICollectionView 혹은 UITableView를 관리하게되면 메인 스레드에서 실행하는 것을 강제하기 때문에 (메인 스레드에서 UI를 갱신해야되기 때문) 동시에 다른 스레드에서 CRUD가 일어나게 되면 문제가 생기게 된다.
스레딩 - Swift SDK - Atlas Device SDK
Atlas Device SDK는 더 이상 사용되지 않습니다. 자세한 내용은 지원 중단 페이지 를 참조하세요.iOS 및 tvOS 앱을 빠르고 응답성이 뛰어나게 만들려면 시각 자료를 배치하고 사용자 상호작용을 처리하
www.mongodb.com
전체
https://www.mongodb.com/ko-kr/docs/atlas/device-sdks/sdk/swift/crud/threading/
스레딩 - Swift SDK - Atlas Device SDK
Atlas Device SDK는 더 이상 사용되지 않습니다. 자세한 내용은 지원 중단 페이지 를 참조하세요.iOS 및 tvOS 앱을 빠르고 응답성이 뛰어나게 만들려면 시각 자료를 배치하고 사용자 상호작용을 처리하
www.mongodb.com
'iOS' 카테고리의 다른 글
[iOS] USB 카메라 연결(2) (0) | 2025.02.19 |
---|---|
[iOS] USB 카메라 연결(1) (0) | 2025.01.09 |
[iOS] 화면 캡처 감지 및 방지 방법 (0) | 2024.12.31 |
[iOS] 오픈소스 라이선스 표시 및 라이브러리 (0) | 2024.12.04 |
[iOS] SwiftGen 사용법 (1) | 2024.10.20 |