@@ -121,20 +121,33 @@ private extension NotificationStore {
121121 /// Updates the read status for the given notification ID(s)
122122 ///
123123 func updateReadStatus( for noteIds: [ Int64 ] , read: Bool , onCompletion: @escaping ( Error ? ) -> Void ) {
124- let remote = NotificationsRemote ( network: network)
124+ /// Optimistically Update
125+ ///
126+ updateLocalNoteReadStatus ( for: noteIds, read: read)
125127
128+ /// On error we'll just mark the Note for Refresh
129+ ///
130+ let remote = NotificationsRemote ( network: network)
126131 remote. updateReadStatus ( noteIds: noteIds, read: read) { error in
127132 guard let error = error else {
128- onCompletion ( nil )
133+
134+ /// What is this about:
135+ /// Notice that there are few conditions in which the Network Request's callback may run *before*
136+ /// the Optimisitc Update, such as in Unit Tests.
137+ /// This may cause the Callback to run before the Read Flag has been toggled, which isn't cool.
138+ /// *FORGIVE ME*, this is a workaround: the onCompletion closure must run after a No-OP in the derived
139+ /// storage.
140+ ///
141+ self . performSharedDerivedStorageNoOp {
142+ onCompletion ( nil )
143+ }
129144 return
130145 }
131146
132147 self . invalidateCache ( for: noteIds) {
133148 onCompletion ( error)
134149 }
135150 }
136-
137- updateLocalNoteReadStatus ( for: noteIds, read: read)
138151 }
139152}
140153
@@ -262,6 +275,16 @@ extension NotificationStore {
262275 DispatchQueue . main. async ( execute: onCompletion)
263276 }
264277 }
278+
279+ /// Runs a No-OP in the Shared Derived Storage. On completion, the callback will be executed on the main thread.
280+ ///
281+ func performSharedDerivedStorageNoOp( onCompletion: @escaping ( ) -> Void ) {
282+ let derivedStorage = type ( of: self ) . sharedDerivedStorage ( with: storageManager)
283+
284+ derivedStorage. perform {
285+ DispatchQueue . main. async ( execute: onCompletion)
286+ }
287+ }
265288}
266289
267290
0 commit comments