From 37bcfc7e78aaf44ad1824f89cad467e54ae1236b Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 27 Nov 2024 19:01:42 +0700 Subject: [PATCH 1/8] Instantiate persistent container as a constant --- .../Storage/CoreData/CoreDataManager.swift | 163 ++++++++---------- 1 file changed, 75 insertions(+), 88 deletions(-) diff --git a/Storage/Storage/CoreData/CoreDataManager.swift b/Storage/Storage/CoreData/CoreDataManager.swift index 35eec88a0ca..4f67d6b97ce 100644 --- a/Storage/Storage/CoreData/CoreDataManager.swift +++ b/Storage/Storage/CoreData/CoreDataManager.swift @@ -7,42 +7,29 @@ import WooFoundation /// public final class CoreDataManager: StorageManagerType { - /// Storage Identifier. - /// - public let name: String - private let crashLogger: CrashLogger - private let modelsInventory: ManagedObjectModelsInventory - /// A serial queue used to ensure there is only one writing operation at a time. private let writerQueue: OperationQueue - /// Module-private designated Initializer. + /// Public designated initializer. /// /// - Parameter name: Identifier to be used for: [database, data model, container]. /// - Parameter crashLogger: allows logging a message of any severity level - /// - Parameter modelsInventory: The models to load when spinning up the Core Data stack. - /// This is automatically generated if `nil`. You would probably only specify this for - /// unit tests to test migration and/or recovery scenarios. /// /// - Important: This should *match* with your actual Data Model file!. /// - init(name: String, - crashLogger: CrashLogger, - modelsInventory: ManagedObjectModelsInventory?) { - self.name = name + public init(name: String, crashLogger: CrashLogger) { self.crashLogger = crashLogger self.writerQueue = OperationQueue() self.writerQueue.name = "com.automattic.woocommerce.CoreDataManager.writer" self.writerQueue.maxConcurrentOperationCount = 1 do { - if let modelsInventory = modelsInventory { - self.modelsInventory = modelsInventory - } else { - self.modelsInventory = try .from(packageName: name, bundle: Bundle(for: type(of: self))) - } + let inventory = try ManagedObjectModelsInventory.from(packageName: name, bundle: Bundle(for: type(of: self))) + self.persistentContainer = Self.createPersistentContainer(with: name, + crashLogger: crashLogger, + modelsInventory: inventory) } catch { // We'll throw a fatalError() because we can't really proceed without a // ManagedObjectModel. @@ -51,17 +38,6 @@ public final class CoreDataManager: StorageManagerType { } } - /// Public designated initializer. - /// - /// - Parameter name: Identifier to be used for: [database, data model, container]. - /// - Parameter crashLogger: allows logging a message of any severity level - /// - /// - Important: This should *match* with your actual Data Model file!. - /// - public convenience init(name: String, crashLogger: CrashLogger) { - self.init(name: name, crashLogger: crashLogger, modelsInventory: nil) - } - /// Returns the Storage associated with the View Thread. /// public var viewStorage: StorageType { @@ -83,60 +59,7 @@ public final class CoreDataManager: StorageManagerType { /// Persistent Container: Holds the full CoreData Stack /// - public lazy var persistentContainer: NSPersistentContainer = { - let container = NSPersistentContainer(name: name, managedObjectModel: modelsInventory.currentModel) - container.persistentStoreDescriptions = [storeDescription] - - let migrationDebugMessages = migrateDataModelIfNecessary(using: container.persistentStoreCoordinator) - - container.loadPersistentStores { [weak self] (storeDescription, error) in - guard let `self` = self, let persistentStoreLoadingError = error else { - return - } - - DDLogError("⛔️ [CoreDataManager] loadPersistentStore failed. Attempting to recover... \(persistentStoreLoadingError)") - - /// Remove the old Store which is either corrupted or has an invalid model we can't migrate from - /// - var persistentStoreRemovalError: Error? - do { - try container.persistentStoreCoordinator.destroyPersistentStore(at: self.storeURL, - ofType: storeDescription.type, - options: nil) - NotificationCenter.default.post(name: .StorageManagerDidResetStorage, object: self) - - } catch { - persistentStoreRemovalError = error - } - - /// Retry! - /// - container.loadPersistentStores { [weak self] (storeDescription, underlyingError) in - guard let underlyingError = underlyingError as NSError? else { - return - } - - let error = CoreDataManagerError.recoveryFailed - let logProperties: [String: Any?] = ["persistentStoreLoadingError": persistentStoreLoadingError, - "persistentStoreRemovalError": persistentStoreRemovalError, - "retryError": underlyingError, - "appState": UIApplication.shared.applicationState.rawValue, - "migrationMessages": migrationDebugMessages] - self?.crashLogger.logFatalErrorAndExit(error, - userInfo: logProperties.compactMapValues { $0 }) - } - - let logProperties: [String: Any?] = ["persistentStoreLoadingError": persistentStoreLoadingError, - "persistentStoreRemovalError": persistentStoreRemovalError, - "appState": UIApplication.shared.applicationState.rawValue, - "migrationMessages": migrationDebugMessages] - self.crashLogger.logMessage("[CoreDataManager] Recovered from persistent store loading error", - properties: logProperties.compactMapValues { $0 }, - level: .info) - } - - return container - }() + public let persistentContainer: NSPersistentContainer /// Saves the derived storage. Note: the closure may be called on a different thread /// @@ -224,6 +147,67 @@ public final class CoreDataManager: StorageManagerType { }, on: .main) } + private static func createPersistentContainer(with storageName: String, + crashLogger: CrashLogger, + modelsInventory: ManagedObjectModelsInventory) -> NSPersistentContainer { + let container = NSPersistentContainer(name: storageName, managedObjectModel: modelsInventory.currentModel) + let storeURL = storeURL(with: storageName) + let storeDescription = storeDescription(with: storageName) + container.persistentStoreDescriptions = [storeDescription] + + let migrationDebugMessages = migrateDataModelIfNecessary(using: container.persistentStoreCoordinator, + storeURL: storeURL, + modelsInventory: modelsInventory) + + container.loadPersistentStores { (storeDescription, error) in + guard let persistentStoreLoadingError = error else { + return + } + + DDLogError("⛔️ [CoreDataManager] loadPersistentStore failed. Attempting to recover... \(persistentStoreLoadingError)") + + /// Remove the old Store which is either corrupted or has an invalid model we can't migrate from + /// + var persistentStoreRemovalError: Error? + do { + try container.persistentStoreCoordinator.destroyPersistentStore(at: storeURL, + ofType: storeDescription.type, + options: nil) + NotificationCenter.default.post(name: .StorageManagerDidResetStorage, object: self) + + } catch { + persistentStoreRemovalError = error + } + + /// Retry! + /// + container.loadPersistentStores { (storeDescription, underlyingError) in + guard let underlyingError = underlyingError as NSError? else { + return + } + + let error = CoreDataManagerError.recoveryFailed + let logProperties: [String: Any?] = ["persistentStoreLoadingError": persistentStoreLoadingError, + "persistentStoreRemovalError": persistentStoreRemovalError, + "retryError": underlyingError, + "appState": UIApplication.shared.applicationState.rawValue, + "migrationMessages": migrationDebugMessages] + crashLogger.logFatalErrorAndExit(error, + userInfo: logProperties.compactMapValues { $0 }) + } + + let logProperties: [String: Any?] = ["persistentStoreLoadingError": persistentStoreLoadingError, + "persistentStoreRemovalError": persistentStoreRemovalError, + "appState": UIApplication.shared.applicationState.rawValue, + "migrationMessages": migrationDebugMessages] + crashLogger.logMessage("[CoreDataManager] Recovered from persistent store loading error", + properties: logProperties.compactMapValues { $0 }, + level: .info) + } + + return container + } + private func deleteAllStoredObjects(in context: NSManagedObjectContext) { let storeCoordinator = persistentContainer.persistentStoreCoordinator do { @@ -245,7 +229,9 @@ public final class CoreDataManager: StorageManagerType { /// Migrates the current persistent store to the latest data model if needed. /// - Returns: an array of debug messages for logging. Please feel free to remove when #2371 is resolved. - private func migrateDataModelIfNecessary(using coordinator: NSPersistentStoreCoordinator) -> [String] { + private static func migrateDataModelIfNecessary(using coordinator: NSPersistentStoreCoordinator, + storeURL: URL, + modelsInventory: ManagedObjectModelsInventory) -> [String] { var debugMessages = [String]() let migrationCheckMessage = "ℹ️ [CoreDataManager] Checking if migration is necessary." @@ -280,7 +266,8 @@ public final class CoreDataManager: StorageManagerType { extension CoreDataManager { /// Returns the PersistentStore Descriptor /// - var storeDescription: NSPersistentStoreDescription { + static func storeDescription(with storageName: String) -> NSPersistentStoreDescription { + let storeURL = storeURL(with: storageName) let description = NSPersistentStoreDescription(url: storeURL) description.shouldAddStoreAsynchronously = false description.shouldMigrateStoreAutomatically = false @@ -294,12 +281,12 @@ extension CoreDataManager { extension CoreDataManager { /// Returns the Store URL (the actual sqlite file!) /// - var storeURL: URL { + static func storeURL(with storageName: String) -> URL { guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { logErrorAndExit("Okay: Missing Documents Folder?") } - return url.appendingPathComponent(name + ".sqlite") + return url.appendingPathComponent(storageName + ".sqlite") } } From bbdb9eae704bd064800223f8889067c32586d543 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 27 Nov 2024 19:05:06 +0700 Subject: [PATCH 2/8] Make viewStorage lazy --- Storage/Storage/CoreData/CoreDataManager.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Storage/Storage/CoreData/CoreDataManager.swift b/Storage/Storage/CoreData/CoreDataManager.swift index 4f67d6b97ce..b19fa7ddb7a 100644 --- a/Storage/Storage/CoreData/CoreDataManager.swift +++ b/Storage/Storage/CoreData/CoreDataManager.swift @@ -40,14 +40,14 @@ public final class CoreDataManager: StorageManagerType { /// Returns the Storage associated with the View Thread. /// - public var viewStorage: StorageType { + public lazy var viewStorage: StorageType = { let context = persistentContainer.viewContext /// This simplifies the process of merging updates from persistent container to view context. /// When disable auto merge, we need to handle merging manually using `NSManagedObjectContextDidSave` notifications. context.automaticallyMergesChangesFromParent = true context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy return context - } + }() /// Returns a shared derived storage instance dedicated for write operations. /// From 9106900c4409fd5309b1772d9e77322d67226d3e Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 27 Nov 2024 19:10:36 +0700 Subject: [PATCH 3/8] Make both viewStorage and writerDerivedStorage constants --- .../Storage/CoreData/CoreDataManager.swift | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/Storage/Storage/CoreData/CoreDataManager.swift b/Storage/Storage/CoreData/CoreDataManager.swift index b19fa7ddb7a..cc00186cc89 100644 --- a/Storage/Storage/CoreData/CoreDataManager.swift +++ b/Storage/Storage/CoreData/CoreDataManager.swift @@ -27,9 +27,26 @@ public final class CoreDataManager: StorageManagerType { do { let inventory = try ManagedObjectModelsInventory.from(packageName: name, bundle: Bundle(for: type(of: self))) - self.persistentContainer = Self.createPersistentContainer(with: name, - crashLogger: crashLogger, - modelsInventory: inventory) + let persistentContainer = Self.createPersistentContainer(with: name, + crashLogger: crashLogger, + modelsInventory: inventory) + self.persistentContainer = persistentContainer + + self.viewStorage = { + let context = persistentContainer.viewContext + /// This simplifies the process of merging updates from persistent container to view context. + /// When disable auto merge, we need to handle merging manually using `NSManagedObjectContextDidSave` notifications. + context.automaticallyMergesChangesFromParent = true + context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy + return context + }() + + self.writerDerivedStorage = { + let backgroundContext = persistentContainer.newBackgroundContext() + backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy + return backgroundContext + }() + } catch { // We'll throw a fatalError() because we can't really proceed without a // ManagedObjectModel. @@ -40,22 +57,11 @@ public final class CoreDataManager: StorageManagerType { /// Returns the Storage associated with the View Thread. /// - public lazy var viewStorage: StorageType = { - let context = persistentContainer.viewContext - /// This simplifies the process of merging updates from persistent container to view context. - /// When disable auto merge, we need to handle merging manually using `NSManagedObjectContextDidSave` notifications. - context.automaticallyMergesChangesFromParent = true - context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy - return context - }() + public let viewStorage: StorageType /// Returns a shared derived storage instance dedicated for write operations. /// - public lazy var writerDerivedStorage: StorageType = { - let backgroundContext = persistentContainer.newBackgroundContext() - backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy - return backgroundContext - }() + public let writerDerivedStorage: StorageType /// Persistent Container: Holds the full CoreData Stack /// From 7c63726ce5b46c6e32391834ac6e3cf6cacd5d4e Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 27 Nov 2024 19:17:06 +0700 Subject: [PATCH 4/8] Restore module-private initializer --- .../Storage/CoreData/CoreDataManager.swift | 64 ++++++++++++------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/Storage/Storage/CoreData/CoreDataManager.swift b/Storage/Storage/CoreData/CoreDataManager.swift index cc00186cc89..384fd89e7e5 100644 --- a/Storage/Storage/CoreData/CoreDataManager.swift +++ b/Storage/Storage/CoreData/CoreDataManager.swift @@ -12,47 +12,65 @@ public final class CoreDataManager: StorageManagerType { /// A serial queue used to ensure there is only one writing operation at a time. private let writerQueue: OperationQueue - /// Public designated initializer. + /// Module-private designated Initializer. /// /// - Parameter name: Identifier to be used for: [database, data model, container]. /// - Parameter crashLogger: allows logging a message of any severity level /// /// - Important: This should *match* with your actual Data Model file!. /// - public init(name: String, crashLogger: CrashLogger) { + init(name: String, + crashLogger: CrashLogger, + modelsInventory: ManagedObjectModelsInventory?) { self.crashLogger = crashLogger self.writerQueue = OperationQueue() self.writerQueue.name = "com.automattic.woocommerce.CoreDataManager.writer" self.writerQueue.maxConcurrentOperationCount = 1 + let inventory: ManagedObjectModelsInventory do { - let inventory = try ManagedObjectModelsInventory.from(packageName: name, bundle: Bundle(for: type(of: self))) - let persistentContainer = Self.createPersistentContainer(with: name, - crashLogger: crashLogger, - modelsInventory: inventory) - self.persistentContainer = persistentContainer - - self.viewStorage = { - let context = persistentContainer.viewContext - /// This simplifies the process of merging updates from persistent container to view context. - /// When disable auto merge, we need to handle merging manually using `NSManagedObjectContextDidSave` notifications. - context.automaticallyMergesChangesFromParent = true - context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy - return context - }() - - self.writerDerivedStorage = { - let backgroundContext = persistentContainer.newBackgroundContext() - backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy - return backgroundContext - }() - + if let modelsInventory { + inventory = modelsInventory + } else { + inventory = try .from(packageName: name, bundle: Bundle(for: type(of: self))) + } } catch { // We'll throw a fatalError() because we can't really proceed without a // ManagedObjectModel. let error = CoreDataManagerError.modelInventoryLoadingFailed(name, error) crashLogger.logFatalErrorAndExit(error, userInfo: nil) } + + let persistentContainer = Self.createPersistentContainer(with: name, + crashLogger: crashLogger, + modelsInventory: inventory) + self.persistentContainer = persistentContainer + + self.viewStorage = { + let context = persistentContainer.viewContext + /// This simplifies the process of merging updates from persistent container to view context. + /// When disable auto merge, we need to handle merging manually using `NSManagedObjectContextDidSave` notifications. + context.automaticallyMergesChangesFromParent = true + context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy + return context + }() + + self.writerDerivedStorage = { + let backgroundContext = persistentContainer.newBackgroundContext() + backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy + return backgroundContext + }() + } + + /// Public designated initializer. + /// + /// - Parameter name: Identifier to be used for: [database, data model, container]. + /// - Parameter crashLogger: allows logging a message of any severity level + /// + /// - Important: This should *match* with your actual Data Model file!. + /// + public convenience init(name: String, crashLogger: CrashLogger) { + self.init(name: name, crashLogger: crashLogger, modelsInventory: nil) } /// Returns the Storage associated with the View Thread. From 6cab93a608249ce531535fff4cb1b9eb939dcea8 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 27 Nov 2024 19:17:11 +0700 Subject: [PATCH 5/8] Update unit tests --- Storage/StorageTests/CoreData/CoreDataManagerTests.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Storage/StorageTests/CoreData/CoreDataManagerTests.swift b/Storage/StorageTests/CoreData/CoreDataManagerTests.swift index 93ef75f84d6..faf2b1e53c5 100644 --- a/Storage/StorageTests/CoreData/CoreDataManagerTests.swift +++ b/Storage/StorageTests/CoreData/CoreDataManagerTests.swift @@ -13,9 +13,8 @@ final class CoreDataManagerTests: XCTestCase { /// Verifies that the Store URL contains the ContextIdentifier string. /// func test_storeUrl_maps_to_sqlite_file_with_context_identifier() { - let manager = CoreDataManager(name: storageIdentifier, crashLogger: MockCrashLogger()) - XCTAssertEqual(manager.storeURL.lastPathComponent, "WooCommerce.sqlite") - XCTAssertEqual(manager.storeDescription.url?.lastPathComponent, "WooCommerce.sqlite") + XCTAssertEqual(CoreDataManager.storeURL(with: storageIdentifier).lastPathComponent, "WooCommerce.sqlite") + XCTAssertEqual(CoreDataManager.storeDescription(with: storageIdentifier).url?.lastPathComponent, "WooCommerce.sqlite") } /// Verifies that the PersistentContainer properly loads the sqlite database. @@ -285,7 +284,7 @@ private extension CoreDataManagerTests { crashLogger: MockCrashLogger(), modelsInventory: modelsInventory) if deleteStoreFiles { - try self.deleteStoreFiles(at: manager.storeURL) + try self.deleteStoreFiles(at: CoreDataManager.storeURL(with: storageIdentifier)) } return manager } From 0affb52e5bf6735fe41870222eb477a6e525530e Mon Sep 17 00:00:00 2001 From: Huong Do Date: Thu, 28 Nov 2024 09:11:52 +0700 Subject: [PATCH 6/8] Make storeURL and storeDescription constants --- .../Storage/CoreData/CoreDataManager.swift | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Storage/Storage/CoreData/CoreDataManager.swift b/Storage/Storage/CoreData/CoreDataManager.swift index 384fd89e7e5..1829f953c14 100644 --- a/Storage/Storage/CoreData/CoreDataManager.swift +++ b/Storage/Storage/CoreData/CoreDataManager.swift @@ -12,6 +12,10 @@ public final class CoreDataManager: StorageManagerType { /// A serial queue used to ensure there is only one writing operation at a time. private let writerQueue: OperationQueue + let storeURL: URL + + let storeDescription: NSPersistentStoreDescription + /// Module-private designated Initializer. /// /// - Parameter name: Identifier to be used for: [database, data model, container]. @@ -41,10 +45,16 @@ public final class CoreDataManager: StorageManagerType { crashLogger.logFatalErrorAndExit(error, userInfo: nil) } + let storeURL = Self.storeURL(with: name) + let storeDescription = Self.storeDescription(with: storeURL) let persistentContainer = Self.createPersistentContainer(with: name, + storeURL: storeURL, + storeDescription: storeDescription, crashLogger: crashLogger, modelsInventory: inventory) self.persistentContainer = persistentContainer + self.storeURL = storeURL + self.storeDescription = storeDescription self.viewStorage = { let context = persistentContainer.viewContext @@ -172,11 +182,11 @@ public final class CoreDataManager: StorageManagerType { } private static func createPersistentContainer(with storageName: String, + storeURL: URL, + storeDescription: NSPersistentStoreDescription, crashLogger: CrashLogger, modelsInventory: ManagedObjectModelsInventory) -> NSPersistentContainer { let container = NSPersistentContainer(name: storageName, managedObjectModel: modelsInventory.currentModel) - let storeURL = storeURL(with: storageName) - let storeDescription = storeDescription(with: storageName) container.persistentStoreDescriptions = [storeDescription] let migrationDebugMessages = migrateDataModelIfNecessary(using: container.persistentStoreCoordinator, @@ -216,8 +226,7 @@ public final class CoreDataManager: StorageManagerType { "retryError": underlyingError, "appState": UIApplication.shared.applicationState.rawValue, "migrationMessages": migrationDebugMessages] - crashLogger.logFatalErrorAndExit(error, - userInfo: logProperties.compactMapValues { $0 }) + crashLogger.logFatalErrorAndExit(error, userInfo: logProperties.compactMapValues { $0 }) } let logProperties: [String: Any?] = ["persistentStoreLoadingError": persistentStoreLoadingError, @@ -225,8 +234,8 @@ public final class CoreDataManager: StorageManagerType { "appState": UIApplication.shared.applicationState.rawValue, "migrationMessages": migrationDebugMessages] crashLogger.logMessage("[CoreDataManager] Recovered from persistent store loading error", - properties: logProperties.compactMapValues { $0 }, - level: .info) + properties: logProperties.compactMapValues { $0 }, + level: .info) } return container @@ -287,11 +296,10 @@ public final class CoreDataManager: StorageManagerType { // MARK: - Descriptors // -extension CoreDataManager { +private extension CoreDataManager { /// Returns the PersistentStore Descriptor /// - static func storeDescription(with storageName: String) -> NSPersistentStoreDescription { - let storeURL = storeURL(with: storageName) + static func storeDescription(with storeURL: URL) -> NSPersistentStoreDescription { let description = NSPersistentStoreDescription(url: storeURL) description.shouldAddStoreAsynchronously = false description.shouldMigrateStoreAutomatically = false From 8de291803fc122d15d825cd971eb65c872a07b48 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Thu, 28 Nov 2024 09:12:00 +0700 Subject: [PATCH 7/8] Fix unit test failures --- .../CoreData/CoreDataManagerTests.swift | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Storage/StorageTests/CoreData/CoreDataManagerTests.swift b/Storage/StorageTests/CoreData/CoreDataManagerTests.swift index faf2b1e53c5..bbd981709bf 100644 --- a/Storage/StorageTests/CoreData/CoreDataManagerTests.swift +++ b/Storage/StorageTests/CoreData/CoreDataManagerTests.swift @@ -13,8 +13,9 @@ final class CoreDataManagerTests: XCTestCase { /// Verifies that the Store URL contains the ContextIdentifier string. /// func test_storeUrl_maps_to_sqlite_file_with_context_identifier() { - XCTAssertEqual(CoreDataManager.storeURL(with: storageIdentifier).lastPathComponent, "WooCommerce.sqlite") - XCTAssertEqual(CoreDataManager.storeDescription(with: storageIdentifier).url?.lastPathComponent, "WooCommerce.sqlite") + let manager = CoreDataManager(name: storageIdentifier, crashLogger: MockCrashLogger()) + XCTAssertEqual(manager.storeURL.lastPathComponent, "WooCommerce.sqlite") + XCTAssertEqual(manager.storeDescription.url?.lastPathComponent, "WooCommerce.sqlite") } /// Verifies that the PersistentContainer properly loads the sqlite database. @@ -279,13 +280,14 @@ private extension CoreDataManagerTests { } func makeManager(using modelsInventory: ManagedObjectModelsInventory, - deletingExistingStoreFiles deleteStoreFiles: Bool) throws -> CoreDataManager { + deletingExistingStoreFiles: Bool) throws -> CoreDataManager { + let storeURL = CoreDataManager.storeURL(with: storageIdentifier) + if deletingExistingStoreFiles { + try deleteStoreFiles(at: storeURL) + } let manager = CoreDataManager(name: storageIdentifier, crashLogger: MockCrashLogger(), modelsInventory: modelsInventory) - if deleteStoreFiles { - try self.deleteStoreFiles(at: CoreDataManager.storeURL(with: storageIdentifier)) - } return manager } From 4de25f36051dac344c8091a993cb87ed6b940382 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Thu, 28 Nov 2024 09:13:50 +0700 Subject: [PATCH 8/8] Update release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 7f8933bcb0d..756b3e38e09 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -5,6 +5,7 @@ - [*] Jetpack Setup: Fixed an issue where the WordPress.com authentication fails when using a passwordless account that's already connected to Jetpack [https://github.com/woocommerce/woocommerce-ios/pull/14501] - [*] Jetpack Setup: Fixed an issue with magic link handling when the app is cold started. [https://github.com/woocommerce/woocommerce-ios/pull/14502] - [**] Media Library: On sites logged in with application password, when picking image from WordPress Media Library, all images will now load correctly. [https://github.com/woocommerce/woocommerce-ios/pull/14444] +- [Internal] Updated CoreDataManager to be thread-safe [https://github.com/woocommerce/woocommerce-ios/pull/14534] 21.2 -----