-
Notifications
You must be signed in to change notification settings - Fork 0
/
Example.swift
141 lines (115 loc) · 4.08 KB
/
Example.swift
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//
// ContentView.swift
// GRDBDatabaseSnapshotExample
//
// Created by Michael on 9/29/19.
// Copyright © 2019 Michael Kirk. All rights reserved.
//
import GRDB
import UIKit
class MyViewController: UIViewController {
lazy var storage: Storage = Storage()
var latestSnapshot: DatabaseSnapshot!
override func loadView() {
self.view = UIView()
view.backgroundColor = .white
view.addSubview(workButton)
workButton.translatesAutoresizingMaskIntoConstraints = false
workButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
workButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: workButton.topAnchor, constant: -16).isActive = true
}
let label: UILabel = {
let label = UILabel()
label.text = "Book Count: ..."
label.textColor = .black
return label
}()
override func viewDidLoad() {
try! storage.migrator.migrate(storage.pool)
try! storage.pool.write { db in
db.add(transactionObserver: self)
}
latestSnapshot = try! storage.pool.makeSnapshot()
}
lazy var workButton: UIButton = {
let button = UIButton(type: .custom)
button.addTarget(self, action: #selector(didPressWorkButton), for: .touchUpInside)
button.setTitle("Do Work", for: .normal)
button.setTitleColor(.black, for: .normal)
return button
}()
func updateUI() {
let bookCount = try! latestSnapshot.read { try Book.fetchCount($0) }
label.text = "Book Count: \(bookCount)"
}
@objc
func didPressWorkButton() {
for _ in 0..<1000 {
DispatchQueue.global().async {
try! self.storage.pool.write { db in
var book = Book(title: UUID().uuidString)
try book.insert(db)
}
}
}
}
}
extension MyViewController: TransactionObserver {
func observes(eventsOfKind eventKind: DatabaseEventKind) -> Bool {
true
}
func databaseDidChange(with event: DatabaseEvent) {
//
}
func databaseDidCommit(_ db: Database) {
// Option 1: rebuild the snapshot. This seems to be what the documentation
// recommends, but it can be quite expensive.
// DispatchQueue.main.async {
// self.latestSnapshot = try! self.storage.pool.makeSnapshot()
// self.updateUI()
// }
// Option 2: Update the snapshot to the latest transaction. This is much
// faster.
DispatchQueue.main.async {
try! self.latestSnapshot.read { db in
try db.commit()
try db.beginTransaction(.deferred)
_ = try Row.fetchCursor(db, sql: "SELECT rootpage FROM sqlite_master LIMIT 1").next()
}
self.updateUI()
}
}
func databaseDidRollback(_ db: Database) {
//
}
}
struct Storage {
let migrator: DatabaseMigrator
let pool: DatabasePool
init() {
self.migrator = {
var migrator = DatabaseMigrator()
migrator.registerMigration("initial") { db in
try db.create(table: "book") { t in
t.autoIncrementedPrimaryKey("id")
t.column("title", .text).collate(.localizedCaseInsensitiveCompare)
}
}
return migrator
}()
self.pool = {
guard let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
fatalError("documentsDir was unexpectedly nil")
}
let dbUrl = documentsDir.appendingPathComponent("database.sqlite")
return try! DatabasePool(path: dbUrl.path)
}()
}
}
struct Book: FetchableRecord, Codable, MutablePersistableRecord {
var title: String
}