@ -2,6 +2,7 @@
import Foundation
import GRDB
import DifferenceKit
// MARK: - P a g e d D a t a b a s e O b s e r v e r
@ -198,6 +199,16 @@ public class PagedDatabaseObserver<ObservedTable, T>: TransactionObserver where
// U p d a t e t h e c a c h e , p a g e I n f o a n d t h e c h a n g e c a l l b a c k
self ? . dataCache . mutate { $0 = finalUpdatedDataCache }
self ? . pageInfo . mutate { $0 = updatedPageInfo }
// M a k e s u r e t h e u p d a t e s r u n o n t h e m a i n t h r e a d
guard Thread . isMainThread else {
DispatchQueue . main . async { [ weak self ] in
self ? . onChangeUnsorted ( finalUpdatedDataCache . values , updatedPageInfo )
}
return
}
self ? . onChangeUnsorted ( finalUpdatedDataCache . values , updatedPageInfo )
}
@ -673,7 +684,12 @@ public class PagedDatabaseObserver<ObservedTable, T>: TransactionObserver where
let updatedLimitInfo : PagedData . PageInfo = PagedData . PageInfo (
pageSize : currentPageInfo . pageSize ,
pageOffset : queryInfo . updatedCacheOffset ,
currentCount : ( currentPageInfo . currentCount + newData . count ) ,
currentCount : {
switch target {
case . reloadCurrent : return currentPageInfo . currentCount
default : return ( currentPageInfo . currentCount + newData . count )
}
} ( ) ,
totalCount : totalCount
)
@ -726,6 +742,12 @@ public class PagedDatabaseObserver<ObservedTable, T>: TransactionObserver where
self ? . isLoadingMoreData . mutate { $0 = false }
}
// M a k e s u r e t h e u p d a t e s r u n o n t h e m a i n t h r e a d
guard Thread . isMainThread else {
DispatchQueue . main . async { triggerUpdates ( ) }
return
}
triggerUpdates ( )
}
@ -996,6 +1018,56 @@ public enum PagedData {
let rowIndex : Int64
}
// MARK: - C o n v e n i e n c e F u n c t i o n s
// FIXME: W o u l d b e g o o d t o c l e a n t h i s u p f u r t h e r i n t h e f u t u r e ( s h o u l d b e a b l e t o d o m o r e p r o c e s s i n g o n B G t h r e a d s )
public static func processAndTriggerUpdates < SectionModel : DifferentiableSection > (
updatedData : [ SectionModel ] ? ,
currentDataRetriever : @ escaping ( ( ) -> [ SectionModel ] ? ) ,
onDataChange : ( ( [ SectionModel ] , StagedChangeset < [ SectionModel ] > ) -> ( ) ) ? ,
onUnobservedDataChange : @ escaping ( ( [ SectionModel ] , StagedChangeset < [ SectionModel ] > ) -> Void )
) {
guard let updatedData : [ SectionModel ] = updatedData else { return }
// N o t e : W h i l e i t w o u l d b e n i c e t o g e n e r a t e t h e c h a n g e s e t o n a b a c k g r o u n d t h r e a d i t i n t r o d u c e s
// a m u l t i - t h r e a d i n g i s s u e w h e r e a d a t a c h a n g e c a n c o m e i n w h i l e t h e t a b l e i s p r o c e s s i n g m u l t i p l e
// u p d a t e s r e s u l t i n g i n t h e d a t a b e i n g i n a p a r t i a l l y u p d a t e d s t a t e ( w h i c h m a k e s t h e s u b s e q u e n t
// t a b l e r e l o a d c r a s h d u e t o i n c o n s i s t e n t s t a t e )
let performUpdates = {
guard let currentData : [ SectionModel ] = currentDataRetriever ( ) else { return }
let changeset : StagedChangeset < [ SectionModel ] > = StagedChangeset (
source : currentData ,
target : updatedData
)
// N o n e e d t o d o a n y t h i n g i f t h e r e w e r e n o c h a n g e s
guard ! changeset . isEmpty else { return }
// I f w e h a v e t h e c a l l b a c k t h e n t r i g g e r i t , o t h e r w i s e j u s t s t o r e t h e c h a n g e s t o b e s e n t
// t o t h e c a l l b a c k i f w e e v e r s t a r t o b s e r v i n g a g a i n ( w h e n w e h a v e t h e c a l l b a c k i t n e e d s
// t o d o t h e d a t a u p d a t i n g a s i t ' s t i e d t o U I u p d a t e s a n d c a n c a u s e c r a s h e s i f n o t u p d a t e d
// i n t h e c o r r e c t o r d e r )
guard let onDataChange : ( ( [ SectionModel ] , StagedChangeset < [ SectionModel ] > ) -> ( ) ) = onDataChange else {
onUnobservedDataChange ( updatedData , changeset )
return
}
onDataChange ( updatedData , changeset )
}
// N o n e e d t o d i s p a t c h t o t h e n e x t r u n l o o p i f w e a r e a l r e a d o n t h e m a i n t h r e a d
guard ! Thread . isMainThread else {
performUpdates ( )
return
}
// R u n a n y c h a n g e s o n t h e m a i n t h r e a d ( a s t h e y w i l l g e n e r a l l y t r i g g e r U I u p d a t e s )
DispatchQueue . main . async {
performUpdates ( )
}
}
// MARK: - I n t e r n a l F u n c t i o n s
fileprivate static func totalCount (