Skip to content

Commit 7cbde6d

Browse files
authored
Try and fix Realm crashes via excessive background tasks (#1874)
Starting in iOS 15, there's a number of crashes happening in the background with Realm. They don't appear to be due to the file lock in the shared app container, but this may help resolve them either way -- easy to see if the next beta doesn't crash a bunch.
1 parent a746086 commit 7cbde6d

27 files changed

+138
-175
lines changed

Sources/App/AppDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
106106
text: "Application Starting" + (launchingForLocation ? " due to location change" : ""),
107107
type: .unknown
108108
)
109-
Current.clientEventStore.addEvent(event)
109+
Current.clientEventStore.addEvent(event).cauterize()
110110

111111
zoneManager = ZoneManager()
112112

Sources/App/ClientEvents/ClientEventTableViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class ClientEventTableViewController: UITableViewController, UISearchResu
6666
alertController.popoverPresentationController?.barButtonItem = sender
6767

6868
alertController.addAction(UIAlertAction(title: L10n.ClientEvents.View.clear, style: .destructive) { _ in
69-
Current.clientEventStore.clearAllEvents()
69+
Current.clientEventStore.clearAllEvents().cauterize()
7070
})
7171
alertController.addAction(UIAlertAction(title: L10n.cancelLabel, style: .cancel, handler: nil))
7272

Sources/App/ClientEvents/LocationHistoryListViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class LocationHistoryListViewController: HAFormViewController {
88

99
@objc private func clear(_ sender: AnyObject?) {
1010
let realm = Current.realm()
11-
try? realm.write {
11+
realm.reentrantWrite {
1212
realm.delete(realm.objects(LocationHistoryEntry.self))
1313
}
1414
}

Sources/App/Settings/AppleWatch/ComplicationEditViewController.swift

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,27 @@ class ComplicationEditViewController: HAFormViewController, TypedRowControllerTy
3030
}
3131

3232
@objc private func save() {
33-
do {
34-
let realm = Current.realm()
35-
try realm.write {
36-
if let name = (form.rowBy(tag: "name") as? TextRow)?.value, name.isEmpty == false {
37-
config.name = name
38-
} else {
39-
config.name = nil
40-
}
41-
if let IsPublic = (form.rowBy(tag: "IsPublic") as? SwitchRow)?.value {
42-
config.IsPublic = IsPublic
43-
} else {
44-
config.IsPublic = true
45-
}
46-
config.Template = displayTemplate
47-
config.Data = getValuesGroupedBySection()
48-
49-
Current.Log.verbose("COMPLICATION \(config) \(config.Data)")
50-
51-
realm.add(config, update: .all)
33+
let realm = Current.realm()
34+
realm.reentrantWrite {
35+
if let name = (form.rowBy(tag: "name") as? TextRow)?.value, name.isEmpty == false {
36+
config.name = name
37+
} else {
38+
config.name = nil
5239
}
53-
} catch {
54-
Current.Log.error(error)
55-
}
40+
if let IsPublic = (form.rowBy(tag: "IsPublic") as? SwitchRow)?.value {
41+
config.IsPublic = IsPublic
42+
} else {
43+
config.IsPublic = true
44+
}
45+
config.Template = displayTemplate
46+
config.Data = getValuesGroupedBySection()
47+
48+
Current.Log.verbose("COMPLICATION \(config) \(config.Data)")
5649

57-
Current.api.then(on: nil) { api in
50+
realm.add(config, update: .all)
51+
}.then(on: nil) {
52+
Current.api
53+
}.then(on: nil) { api in
5854
api.updateComplications(passively: false)
5955
}.cauterize()
6056

@@ -76,15 +72,11 @@ class ComplicationEditViewController: HAFormViewController, TypedRowControllerTy
7672
alert.addAction(UIAlertAction(
7773
title: L10n.Watch.Configurator.Delete.button, style: .destructive, handler: { [config] _ in
7874
let realm = Current.realm()
79-
do {
80-
try realm.write {
81-
realm.delete(config)
82-
}
83-
} catch {
84-
Current.Log.error(error)
85-
}
86-
87-
Current.api.then(on: nil) { api in
75+
realm.reentrantWrite {
76+
realm.delete(config)
77+
}.then(on: nil) {
78+
Current.api
79+
}.then(on: nil) { api in
8880
api.updateComplications(passively: false)
8981
}.cauterize()
9082

Sources/App/Settings/Notifications/NotificationActionConfigurator.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,7 @@ class NotificationActionConfigurator: HAFormViewController, TypedRowControllerTy
234234

235235
let formVals = form.values(includeHidden: true)
236236

237-
// swiftlint:disable:next force_try
238-
try! realm.write {
237+
realm.reentrantWrite {
239238
// swiftlint:disable force_cast
240239
if self.newAction {
241240
self.action.Identifier = formVals["identifier"] as! String

Sources/App/Settings/Notifications/NotificationCategoryConfigurator.swift

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,8 @@ class NotificationCategoryConfigurator: HAFormViewController, TypedRowController
124124
if !newCategory {
125125
$0.value = self.category.Name
126126
}
127-
}.onChange { row in
128-
// swiftlint:disable:next force_try
129-
try! self.realm.write {
127+
}.onChange { [realm] row in
128+
realm.reentrantWrite {
130129
if let value = row.value {
131130
self.category.Name = value
132131
}
@@ -141,9 +140,8 @@ class NotificationCategoryConfigurator: HAFormViewController, TypedRowController
141140
$0.value = self.category.Identifier
142141
$0.disabled = true
143142
}
144-
}.onChange { row in
145-
// swiftlint:disable:next force_try
146-
try! self.realm.write {
143+
}.onChange { [realm] row in
144+
realm.reentrantWrite {
147145
if let value = row.value {
148146
self.category.Identifier = value
149147
}
@@ -167,9 +165,8 @@ class NotificationCategoryConfigurator: HAFormViewController, TypedRowController
167165
} else {
168166
$0.value = L10n.NotificationsConfigurator.Category.Rows.HiddenPreviewPlaceholder.default
169167
}
170-
}.onChange { row in
171-
// swiftlint:disable:next force_try
172-
try! self.realm.write {
168+
}.onChange { [realm] row in
169+
realm.reentrantWrite {
173170
if let value = row.value {
174171
self.category.HiddenPreviewsBodyPlaceholder = value
175172
}
@@ -193,9 +190,8 @@ class NotificationCategoryConfigurator: HAFormViewController, TypedRowController
193190
} else {
194191
$0.value = L10n.NotificationsConfigurator.Category.Rows.CategorySummary.default
195192
}
196-
}.onChange { row in
197-
// swiftlint:disable:next force_try
198-
try! self.realm.write {
193+
}.onChange { [realm] row in
194+
realm.reentrantWrite {
199195
if let value = row.value {
200196
self.category.CategorySummaryFormat = value
201197
}
@@ -260,8 +256,7 @@ class NotificationCategoryConfigurator: HAFormViewController, TypedRowController
260256
if let index = indexes.first?.section, let section = form.allSections[index] as? MultivaluedSection {
261257
let deletedIDs = rows.compactMap(\.tag)
262258

263-
// swiftlint:disable:next force_try
264-
try! realm.write {
259+
realm.reentrantWrite {
265260
// if the category isn't persisted yet, we need to remove the actions manually
266261
category.Actions.remove(
267262
atOffsets: category.Actions
@@ -319,7 +314,7 @@ class NotificationCategoryConfigurator: HAFormViewController, TypedRowController
319314

320315
row.presentationMode = PresentationMode.show(controllerProvider: ControllerProvider.callback { [category] in
321316
NotificationActionConfigurator(category: category, action: action)
322-
}, onDismiss: { vc in
317+
}, onDismiss: { [realm, weak self] vc in
323318
vc.navigationController?.popViewController(animated: true)
324319

325320
if let vc = vc as? NotificationActionConfigurator {
@@ -330,8 +325,8 @@ class NotificationCategoryConfigurator: HAFormViewController, TypedRowController
330325
vc.row.updateCell()
331326
Current.Log.verbose("action \(vc.action)")
332327

333-
// swiftlint:disable:next force_try
334-
try! self.realm.write {
328+
realm.reentrantWrite {
329+
guard let self = self else { return }
335330
// only add into realm if the category is also persisted
336331
self.category.realm?.add(vc.action, update: .all)
337332

@@ -340,7 +335,7 @@ class NotificationCategoryConfigurator: HAFormViewController, TypedRowController
340335
}
341336
}
342337

343-
self.updatePreview()
338+
self?.updatePreview()
344339
}
345340
})
346341
}

Sources/App/Settings/Notifications/NotificationCategoryListViewController.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,7 @@ class NotificationCategoryListViewController: HAFormViewController {
106106
Current.Log.verbose("Saving category! \(vc.category)")
107107

108108
let realm = Current.realm()
109-
110-
// swiftlint:disable:next force_try
111-
try! realm.write {
109+
realm.reentrantWrite {
112110
realm.add(vc.category, update: .all)
113111
}
114112
}
@@ -128,8 +126,7 @@ class NotificationCategoryListViewController: HAFormViewController {
128126
let realm = Current.realm()
129127

130128
if (rows.first as? ButtonRowWithPresent<NotificationCategoryConfigurator>) != nil {
131-
// swiftlint:disable:next force_try
132-
try! realm.write {
129+
realm.reentrantWrite {
133130
realm.delete(realm.objects(NotificationCategory.self).filter("Identifier IN %@", deletedIDs))
134131
}
135132
}

Sources/App/Settings/SettingsDetailViewController.swift

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -538,8 +538,7 @@ class SettingsDetailViewController: HAFormViewController, TypedRowControllerType
538538

539539
if (rows.first as? ButtonRowWithPresent<ActionConfigurator>) != nil {
540540
Current.Log.verbose("Removed row is ActionConfiguration \(deletedIDs)")
541-
// swiftlint:disable:next force_try
542-
try! realm.write {
541+
realm.reentrantWrite {
543542
realm.delete(realm.objects(Action.self).filter("ID IN %@", deletedIDs))
544543
}
545544
}
@@ -576,12 +575,8 @@ class SettingsDetailViewController: HAFormViewController, TypedRowControllerType
576575
_ = vc.navigationController?.popViewController(animated: true)
577576

578577
if let vc = vc as? ActionConfigurator, vc.shouldSave, let realm = rlmScene.realm {
579-
do {
580-
try realm.write {
581-
realm.add(vc.action, update: .all)
582-
}
583-
} catch {
584-
Current.Log.error("Error while saving to Realm!: \(error)")
578+
realm.reentrantWrite {
579+
realm.add(vc.action, update: .all)
585580
}
586581
}
587582
})
@@ -661,16 +656,11 @@ class SettingsDetailViewController: HAFormViewController, TypedRowControllerType
661656
Current.Log.verbose("Saving action! \(vc.action)")
662657

663658
let realm = Current.realm()
664-
665-
do {
666-
try realm.write {
667-
realm.add(vc.action, update: .all)
668-
}
669-
659+
realm.reentrantWrite {
660+
realm.add(vc.action, update: .all)
661+
}.done {
670662
self?.updatePositions()
671-
} catch let error as NSError {
672-
Current.Log.error("Error while saving to Realm!: \(error)")
673-
}
663+
}.cauterize()
674664
}
675665
})
676666
}

Sources/App/ZoneManager/ZoneManager.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class ZoneManager {
102102
// ^ not tap for this side effect because we don't want to do this on failure
103103
guard let self = self else { return }
104104
self.sync(zones: AnyCollection(self.zones))
105-
}.done {
105+
}.then {
106106
Current.clientEventStore.addEvent(ClientEvent(
107107
text: "Updated location",
108108
type: .locationUpdate,
@@ -118,7 +118,7 @@ class ZoneManager {
118118
text: "Didn't update: \(error.localizedDescription)",
119119
type: .locationUpdate,
120120
payload: updatedPayload
121-
))
121+
)).cauterize()
122122
}
123123
}
124124

@@ -161,7 +161,7 @@ class ZoneManager {
161161
payload: [
162162
"region": String(describing: region),
163163
]
164-
))
164+
)).cauterize()
165165
locationManager.stopMonitoring(for: region)
166166
}
167167

@@ -172,7 +172,7 @@ class ZoneManager {
172172
payload: [
173173
"region": String(describing: region),
174174
]
175-
))
175+
)).cauterize()
176176

177177
collector.ignoreNextState(for: region)
178178
locationManager.startMonitoring(for: region)

Sources/App/ZoneManager/ZoneManagerIgnoreReason.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ enum ZoneManagerIgnoreReason: LocalizedError, Equatable {
88
case unknownRegion
99
case zoneDisabled
1010
case ignoredSSID(String)
11-
case zoneUpdateFailed(NSError) // NSError so Equatable for laziness
1211
case beaconExitIgnored
1312
case recentlyUpdated
1413

@@ -28,8 +27,6 @@ enum ZoneManagerIgnoreReason: LocalizedError, Equatable {
2827
return "zone has tracking disabled"
2928
case let .ignoredSSID(ssid):
3029
return "ignored due to ssid \(ssid)"
31-
case let .zoneUpdateFailed(error):
32-
return "failed to update realm: \(error.localizedDescription)"
3330
case .beaconExitIgnored:
3431
return "beacon exit ignored"
3532
case .recentlyUpdated:

0 commit comments

Comments
 (0)