diff --git a/Account/Sources/Account/CloudKit/CloudKitArticlesZoneDelegate.swift b/Account/Sources/Account/CloudKit/CloudKitArticlesZoneDelegate.swift index a5462e036..0f5daf86e 100644 --- a/Account/Sources/Account/CloudKit/CloudKitArticlesZoneDelegate.swift +++ b/Account/Sources/Account/CloudKit/CloudKitArticlesZoneDelegate.swift @@ -43,10 +43,12 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate { case .success(let pendingStarredStatusArticleIDs): self.delete(recordKeys: deleted, pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs) { - self.update(records: changed, - pendingReadStatusArticleIDs: pendingReadStatusArticleIDs, - pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs, - completion: completion) + Task { @MainActor in + self.update(records: changed, + pendingReadStatusArticleIDs: pendingReadStatusArticleIDs, + pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs, + completion: completion) + } } case .failure(let error): @@ -58,11 +60,8 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate { os_log(.error, log: self.log, "Error occurred getting pending read status records: %@", error.localizedDescription) completion(.failure(CloudKitZoneError.unknown)) } - } - } - } private extension CloudKitArticlesZoneDelegate { @@ -84,7 +83,7 @@ private extension CloudKitArticlesZoneDelegate { } } - func update(records: [CKRecord], pendingReadStatusArticleIDs: Set, pendingStarredStatusArticleIDs: Set, completion: @escaping (Result) -> Void) { + @MainActor func update(records: [CKRecord], pendingReadStatusArticleIDs: Set, pendingStarredStatusArticleIDs: Set, completion: @escaping (Result) -> Void) { let receivedUnreadArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "0" }).map({ stripPrefix($0.externalID) })) let receivedReadArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "1" }).map({ stripPrefix($0.externalID) })) @@ -101,40 +100,48 @@ private extension CloudKitArticlesZoneDelegate { group.enter() account?.markAsUnread(updateableUnreadArticleIDs) { result in - if case .failure(let databaseError) = result { - errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing unread statuses: %@", databaseError.localizedDescription) + MainActor.assumeIsolated { + if case .failure(let databaseError) = result { + errorOccurred = true + os_log(.error, log: self.log, "Error occurred while storing unread statuses: %@", databaseError.localizedDescription) + } + group.leave() } - group.leave() } - + group.enter() account?.markAsRead(updateableReadArticleIDs) { result in - if case .failure(let databaseError) = result { - errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing read statuses: %@", databaseError.localizedDescription) + MainActor.assumeIsolated { + if case .failure(let databaseError) = result { + errorOccurred = true + os_log(.error, log: self.log, "Error occurred while storing read statuses: %@", databaseError.localizedDescription) + } + group.leave() } - group.leave() } - + group.enter() account?.markAsUnstarred(updateableUnstarredArticleIDs) { result in - if case .failure(let databaseError) = result { - errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing unstarred statuses: %@", databaseError.localizedDescription) + MainActor.assumeIsolated { + if case .failure(let databaseError) = result { + errorOccurred = true + os_log(.error, log: self.log, "Error occurred while storing unstarred statuses: %@", databaseError.localizedDescription) + } + group.leave() } - group.leave() } - + group.enter() account?.markAsStarred(updateableStarredArticleIDs) { result in - if case .failure(let databaseError) = result { - errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing starred statuses: %@", databaseError.localizedDescription) + MainActor.assumeIsolated { + if case .failure(let databaseError) = result { + errorOccurred = true + os_log(.error, log: self.log, "Error occurred while storing starred statuses: %@", databaseError.localizedDescription) + } + group.leave() } - group.leave() } - + group.enter() compressionQueue.async { let parsedItems = records.compactMap { self.makeParsedItem($0) } @@ -144,26 +151,27 @@ private extension CloudKitArticlesZoneDelegate { for (feedID, parsedItems) in feedIDsAndItems { group.enter() self.account?.update(feedID, with: parsedItems, deleteOlder: false) { result in - switch result { - case .success(let articleChanges): - guard let deletes = articleChanges.deletedArticles, !deletes.isEmpty else { - group.leave() - return - } - let syncStatuses = deletes.map { SyncStatus(articleID: $0.articleID, key: .deleted, flag: true) } - self.database.insertStatuses(syncStatuses) { _ in + MainActor.assumeIsolated { + switch result { + case .success(let articleChanges): + guard let deletes = articleChanges.deletedArticles, !deletes.isEmpty else { + group.leave() + return + } + let syncStatuses = deletes.map { SyncStatus(articleID: $0.articleID, key: .deleted, flag: true) } + self.database.insertStatuses(syncStatuses) { _ in + group.leave() + } + case .failure(let databaseError): + errorOccurred = true + os_log(.error, log: self.log, "Error occurred while storing articles: %@", databaseError.localizedDescription) group.leave() } - case .failure(let databaseError): - errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing articles: %@", databaseError.localizedDescription) - group.leave() } + group.leave() } } - group.leave() } - } group.notify(queue: DispatchQueue.main) { diff --git a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift index 65af2f95d..3ec61078d 100644 --- a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift @@ -47,9 +47,9 @@ final class FeedbinAccountDelegate: AccountDelegate { init(dataFolder: String, transport: Transport?) { - let databaseFilePath = (dataFolder as NSString).appendingPathComponent("Sync.sqlite3") - database = SyncDatabase(databaseFilePath: databaseFilePath) - + let databasePath = (dataFolder as NSString).appendingPathComponent("Sync.sqlite3") + database = SyncDatabase(databasePath: databasePath) + if transport != nil { caller = FeedbinAPICaller(transport: transport!) diff --git a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift index 727e34a05..e21a5a741 100644 --- a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift +++ b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift @@ -631,12 +631,18 @@ final class NewsBlurAccountDelegate: AccountDelegate { /// Suspend the SQLLite databases func suspendDatabase() { - database.suspend() + + Task { + await database.suspend() + } } /// Make sure no SQLite databases are open and we are ready to issue network requests. func resume() { - caller.resume() - database.resume() + + Task { + caller.resume() + await database.resume() + } } } diff --git a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift index da676d0f7..b14c52d31 100644 --- a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift +++ b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift @@ -75,9 +75,9 @@ final class ReaderAPIAccountDelegate: AccountDelegate { var refreshProgress = DownloadProgress(numberOfTasks: 0) init(dataFolder: String, transport: Transport?, variant: ReaderAPIVariant, secretsProvider: SecretsProvider) { - let databaseFilePath = (dataFolder as NSString).appendingPathComponent("Sync.sqlite3") - database = SyncDatabase(databaseFilePath: databaseFilePath) - + let databasePath = (dataFolder as NSString).appendingPathComponent("Sync.sqlite3") + database = SyncDatabase(databasePath: databasePath) + if transport != nil { caller = ReaderAPICaller(transport: transport!, secretsProvider: secretsProvider) } else {