티스토리 뷰
reaml의 결과 데이터는 항상 최신 데이터를 반환합니다. 즉, 결과를 다시 로드할 필요가 없습니다.
하지만 데이터와 다르게 UI는 자동으로 없데이트 되지 않기 때문에 수동으로 업데이트해줄 필요가 있습니다.
수동으로 업데이트하기 위해서는 데이터가 변견된 시점을 알아야 되는데, 이 문제를 Notification 으로 해결할 수 있습니다.
Result 객체에 Notification을 설정하면, 해당 객체를 관찰하면서 데이터의 변경이 발생할 때 호출되어 변경 시점을 알 수 있습니다.
그럼 바로 코드로 알아 보겠습니다!
아래는 user 데이터를 반환받은 결과 객체에 관찰자(observer)를 설정하는 코드입니다.
let tableView = UITableView()
var users: Result<User>?
var notificationToken: NotificationToken?
override func viewDidLoad() {
super.viewDidLoad()
users = realm.objects(User.self) // 1
// 2
notificationToken = users?.observe { [unowned self] changes in
switch changes {
// 3
case .initial(let users):
print("Initial count: \(users.count)")
self.tableView.reloadData()
// 4
case .update(let users, let deletions, let insertions, let modifications):
print("Update count: \(users.count)")
print("Delete count: \(deletions.count)")
print("Insert count: \(insertions.count)")
print("Modification count: \(modifications.count)")
case .error(let error):
fatalError("\(error)")
}
}
}
출력: Intial count: 3
- user 데이터를 가져옵니다.
- 데이터의 결과 객체에 관찰자를 추가합니다. 클로저의 파라미터 값인 changes는 RealmCollectionChange 값인 열거형 타입으로, 데이터 변경에 대한 정보를 담고 있습니다.
- 처음 실행시 호출됩니다. 이는 관찰자를 추가한 그 시점에 한번만 호출되고, 초기 데이터를 UI에 업데이트하는 시점으로 좋습니다.
- 데이터의 변경(insert, delete, update)이 발생할 경우 호출됩니다. deletions, insertions, modifications 파라미터는 [Int] 타입이며, 변경(삭제, 추가, 수정)된 인덱스 값을 나타냅니다.
아래는 위의 내용을 토대로 관찰자를 추가해서 데이터가 변경될 때 마다 tableView를 업데이트해주는 코드입니다.
override func viewDidLoad() {
super.viewDidLoad()
users = realm.objects(User.self)
notificationToken = users?.observe { [unowned self] changes in
switch changes {
case .initial(let users):
self.tableView.reloadData()
case .update(let users, let deletions, let insertions, let modifications):
if deletions.count > 0 {
deleteRow(at: deletions)
}
if insertions.count > 0 {
insertRow(at: insertions)
}
if modifications.count > 0 {
updateRow(at: modifications)
}
case .error(let error):
fatalError("\(error)")
}
}
}
private func insertRow(at indexs: [Int]) {
tableView.beginUpdates()
let indexPaths = indexs.map { IndexPath(item: $0, section: 0) }
tableView.insertRows(at: indexPaths, with: .automatic)
tableView.endUpdates()
}
private func deleteRow(at indexs: [Int]) {
tableView.beginUpdates()
let indexPaths = indexs.map { IndexPath(item: $0, section: 0) }
tableView.deleteRows(at: indexPaths, with: .automatic)
tableView.endUpdates()
}
private func updateRow(at indexs: [Int]) {
let indexPaths = indexs.map { IndexPath(item: $0, section: 0) }
tableView.reloadRows(at: indexPaths, with: .automatic)
}
콜렉션뿐만 아니라 하나의 객체 수준에도 관찰자를 추가할 수 있는데, 아래는 User 객체와 To-One 관계로 있는 IDCard 객체에 관찰자를 추가하는 경우입니다.
let user = realm.object(ofType: User.self, forPrimaryKey: 1)
// 1
let notificationTokenForIdCard = users?.idCard?.observe { [unowned self] changes in
switch changes {
case .change(let properties): // 2
for property in properties {
print(property.name)
print(property.oldValue)
print(property.newValue)
}
case .deleted: // 3
print("delete object.")
case .error(let error):
fatalError("\(error)")
}
}
- user의 IDCard 객체에 관찰자를 설정합니다.
- 객체의 데이터가 변경될 경우 호출되며, properties에는 변경된 값에 대한 내용과 변경 전후의 객체 정보를 제공합니다.
- 객체가 삭제될 경우 호출되며, 관찰자 대상자가 없어졌기 때문에 더이상 관찰하지 않습니다.
Reference
https://medium.com/@aliakhtar_16369/realm-notifications-realmswift-part-2-60c66ab99ea9
'Swift > Realm' 카테고리의 다른 글
[swift] Realm 시작하기 (0) | 2020.03.26 |
---|
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- permission error
- xib
- customAlertView
- RECORDING
- Video
- AssociatedObject
- http live streaming
- UIControl
- AVKit
- Cleancode
- Coordinator
- database
- ssh
- carousel
- NIB
- CollectionView
- AVFoundation
- testing
- IOS
- HLS
- BaseViewController
- Closure
- UIButton
- Design Pattern
- Realm
- UIBarButtonItem
- Swift
- m3u8
- TDD
- pagingView
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함