Skip to content

Commit

Permalink
[Background Mapping] Avoid crash when accessing DTOs while DB is bein…
Browse files Browse the repository at this point in the history
…g recreated (#2934)

* Make sure the object is valid before mapping it

* Keep track of DB being deleted on BackgroundDatabaseObserver

* Improve API to track if database is being removed

---------

Co-authored-by: Pol Quintana <[email protected]>
  • Loading branch information
nuno-vieira and polqf committed Dec 13, 2023
1 parent f8bdc61 commit e6079f9
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ class BackgroundDatabaseObserver<Item, DTO: NSManagedObject> {

private var _isInitialized: Bool = false
private var isInitialized: Bool {
get {
queue.sync { _isInitialized }
}
set {
queue.async(flags: .barrier) {
self._isInitialized = newValue
}
}
get { queue.sync { _isInitialized } }
set { queue.async(flags: .barrier) { self._isInitialized = newValue } }
}

private var _isDeletingDatabase: Bool = false
private var isDeletingDatabase: Bool {
get { queue.sync { _isDeletingDatabase }}
set { queue.async(flags: .barrier) { self._isDeletingDatabase = newValue } }
}

deinit {
Expand Down Expand Up @@ -104,7 +104,7 @@ class BackgroundDatabaseObserver<Item, DTO: NSManagedObject> {
/// Starts observing the changes in the database.
/// - Throws: An error if the fetch fails.
func startObserving() throws {
guard !isInitialized else { return }
guard !isInitialized && !isDeletingDatabase else { return }
isInitialized = true

do {
Expand Down Expand Up @@ -191,7 +191,8 @@ class BackgroundDatabaseObserver<Item, DTO: NSManagedObject> {

var items: [Item?] = []
items = objects.map { [weak self] in
try? self?.itemCreator($0)
guard self?.isDeletingDatabase == false else { return nil }
return try? self?.itemCreator($0)
}

let sorting = self.sorting
Expand All @@ -213,6 +214,11 @@ extension BackgroundDatabaseObserver: DatabaseObserverRemovalListener {
isBackground: true,
frc: frc,
changeAggregator: changeAggregator,
onStart: { [weak self] in
self?.queue.async(flags: .barrier) {
self?._isDeletingDatabase = true
}
},
onItemsRemoval: { [weak self] completion in
self?.queue.async(flags: .barrier) {
self?._items = []
Expand All @@ -224,6 +230,7 @@ extension BackgroundDatabaseObserver: DatabaseObserverRemovalListener {
onCompletion: { [weak self] in
guard let self = self else { return }
self.queue.async(flags: .barrier) {
self._isDeletingDatabase = false
self._isInitialized = false

DispatchQueue.main.async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ extension DatabaseObserverRemovalListener {
isBackground: Bool,
frc: NSFetchedResultsController<DTO>,
changeAggregator: ListChangeAggregator<DTO, Item>,
onStart: @escaping () -> Void,
onItemsRemoval: @escaping (@escaping () -> Void) -> Void,
onCompletion: @escaping () -> Void
) {
Expand All @@ -30,6 +31,7 @@ extension DatabaseObserverRemovalListener {
) { [weak frc, weak context, weak changeAggregator] _ in
guard let frc = frc, let context = context, let changeAggregator = changeAggregator else { return }
guard let fetchResultsController = frc as? NSFetchedResultsController<NSFetchRequestResult> else { return }
onStart()

let removeItems = {
// Simulate ChangeObserver callbacks like all data are being removed
Expand Down Expand Up @@ -76,4 +78,21 @@ extension DatabaseObserverRemovalListener {
notificationCenter?.removeObserver(didRemoveAllDataNotificationObserver)
}
}

func listenForRemoveAllDataNotifications<Item, DTO: NSManagedObject>(
isBackground: Bool,
frc: NSFetchedResultsController<DTO>,
changeAggregator: ListChangeAggregator<DTO, Item>,
onItemsRemoval: @escaping (@escaping () -> Void) -> Void,
onCompletion: @escaping () -> Void
) {
listenForRemoveAllDataNotifications(
isBackground: isBackground,
frc: frc,
changeAggregator: changeAggregator,
onStart: {},
onItemsRemoval: onItemsRemoval,
onCompletion: onCompletion
)
}
}

0 comments on commit e6079f9

Please sign in to comment.