From 6a51ce52fcd9ae2c0d12c4094b79417e3f139d14 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Wed, 8 Mar 2023 14:25:41 +1300 Subject: [PATCH 1/3] Add another `performAndSave` overload that captures a successful result --- .../Classes/Utility/ContextManager.swift | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/WordPress/Classes/Utility/ContextManager.swift b/WordPress/Classes/Utility/ContextManager.swift index 4ade7fbf0555..9b64dc9b4769 100644 --- a/WordPress/Classes/Utility/ContextManager.swift +++ b/WordPress/Classes/Utility/ContextManager.swift @@ -8,6 +8,18 @@ let ContextManagerModelNameCurrent = "$CURRENT" public protocol CoreDataStackSwift: CoreDataStack { + /// Execute the given block with a background context and save the changes. + /// + /// This function _does not block_ its running thread. The block is executed in background and its return value + /// is passed onto the `completion` block which is executed on the given `queue`. + /// + /// - Parameters: + /// - block: A closure which uses the given `NSManagedObjectContext` to make Core Data model changes. + /// - completion: A closure which is called with the return value of the `block`, after the changed made + /// by the `block` is saved. + /// - queue: A queue on which to execute the completion block. + func performAndSave(_ block: @escaping (NSManagedObjectContext) -> T, completion: ((T) -> Void)?, on queue: DispatchQueue) + func performAndSave(_ block: @escaping (NSManagedObjectContext) throws -> T, completion: ((Result) -> Void)?, on queue: DispatchQueue) func performAndSave(_ block: @escaping (NSManagedObjectContext) throws -> T) async throws -> T @@ -111,6 +123,17 @@ public class ContextManager: NSObject, CoreDataStack, CoreDataStackSwift { }) } + public func performAndSave(_ block: @escaping (NSManagedObjectContext) -> T, completion: ((T) -> Void)?, on queue: DispatchQueue) { + performAndSave( + block, + completion: { (result: Result) in + // It's safe to force-unwrap here, since the `block` does not throw an error. + completion?(try! result.get()) + }, + on: queue + ) + } + public func performAndSave(_ block: @escaping (NSManagedObjectContext) throws -> T) async throws -> T { try await withCheckedThrowingContinuation { continuation in performAndSave(block, completion: continuation.resume(with:), on: DispatchQueue.global()) From c9c46034be5bb743bf29ce77762cb41839cd99c0 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Wed, 8 Mar 2023 14:53:41 +1300 Subject: [PATCH 2/3] Change a synchronouse performAndSave to asynchronous call --- .../Services/NotificationSyncMediator.swift | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/WordPress/Classes/Services/NotificationSyncMediator.swift b/WordPress/Classes/Services/NotificationSyncMediator.swift index f30b3bed6dc0..ea96f124b6fa 100644 --- a/WordPress/Classes/Services/NotificationSyncMediator.swift +++ b/WordPress/Classes/Services/NotificationSyncMediator.swift @@ -25,7 +25,7 @@ let NotificationSyncMediatorDidUpdateNotifications = "NotificationSyncMediatorDi final class NotificationSyncMediator { /// Returns the Main Managed Context /// - fileprivate let contextManager: CoreDataStack + fileprivate let contextManager: CoreDataStackSwift /// Sync Service Remote /// @@ -71,7 +71,7 @@ final class NotificationSyncMediator { /// - manager: ContextManager Instance /// - wordPressComRestApi: The WordPressComRestApi that should be used. /// - init?(manager: CoreDataStack, dotcomAPI: WordPressComRestApi) { + init?(manager: CoreDataStackSwift, dotcomAPI: WordPressComRestApi) { guard dotcomAPI.hasCredentials() else { return nil } @@ -311,7 +311,7 @@ private extension NotificationSyncMediator { /// func determineUpdatedNotes(with remoteHashes: [RemoteNotification], completion: @escaping (([String]) -> Void)) { Self.operationQueue.addOperation(AsyncBlockOperation { [contextManager] done in - contextManager.performAndSave { context in + contextManager.performAndSave({ context in let remoteIds = remoteHashes.map { $0.notificationId } let predicate = NSPredicate(format: "(notificationId IN %@)", remoteIds) var localHashes = [String: String]() @@ -320,19 +320,16 @@ private extension NotificationSyncMediator { localHashes[note.notificationId] = note.notificationHash ?? "" } - let outdatedIds = remoteHashes + return remoteHashes .filter { remote in let localHash = localHashes[remote.notificationId] return localHash == nil || localHash != remote.notificationHash } .map { $0.notificationId } - - DispatchQueue.main.async { - completion(outdatedIds) - } - + }, completion: { outdatedIds in + completion(outdatedIds) done() - } + }, on: .main) }) } From 1b0cdf997145a8bbcdda8ce2466403d249af9670 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Thu, 9 Mar 2023 14:05:43 +1300 Subject: [PATCH 3/3] Change a property scope from fileprivate to private Co-authored-by: Gio Lodi --- WordPress/Classes/Services/NotificationSyncMediator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/Services/NotificationSyncMediator.swift b/WordPress/Classes/Services/NotificationSyncMediator.swift index ea96f124b6fa..76039605f329 100644 --- a/WordPress/Classes/Services/NotificationSyncMediator.swift +++ b/WordPress/Classes/Services/NotificationSyncMediator.swift @@ -25,7 +25,7 @@ let NotificationSyncMediatorDidUpdateNotifications = "NotificationSyncMediatorDi final class NotificationSyncMediator { /// Returns the Main Managed Context /// - fileprivate let contextManager: CoreDataStackSwift + private let contextManager: CoreDataStackSwift /// Sync Service Remote ///