diff --git a/README.md b/README.md index 8edd35c..327dff0 100644 --- a/README.md +++ b/README.md @@ -766,13 +766,13 @@ While the syntax is straightforward, CoreStore does not just naively insert a ne - If the entity belongs to multiple stores, an assertion failure will be raised. **This is also a programmer error and should never occur in production code.** Normally, with Core Data you can insert an object in this state but saving the `NSManagedObjectContext` will always fail. CoreStore checks this for you at creation time when it makes sense (not during save). If the entity exists in multiple configurations, you need to provide the configuration name for the destination persistent store: - - let person = transaction.create(Into("Config1")) - +```swift +let person = transaction.create(Into("Config1")) +``` or if the persistent store is the auto-generated "Default" configuration, specify `nil`: - - let person = transaction.create(Into(nil)) - +```swift +let person = transaction.create(Into(nil)) +``` Note that if you do explicitly specify the configuration name, CoreStore will only try to insert the created object to that particular store and will fail if that store is not found; it will not fall back to any other configuration that the entity belongs to. ### Updating objects diff --git a/Sources/BaseDataTransaction.swift b/Sources/BaseDataTransaction.swift index b61bd50..64c1790 100644 --- a/Sources/BaseDataTransaction.swift +++ b/Sources/BaseDataTransaction.swift @@ -213,6 +213,25 @@ public /*abstract*/ class BaseDataTransaction { // MARK: Inspecting Pending Objects + + /** + Returns `true` if the object has any property values changed. This method should not be called after the `commit()` method was called. + + - parameter entity: the `DynamicObject` instance + - returns: `true` if the object has any property values changed. + */ + public func objectHasPersistentChangedValues(_ entity: D) -> Bool { + + CoreStore.assert( + self.isRunningInAllowedQueue(), + "Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue." + ) + CoreStore.assert( + !self.isCommitted, + "Attempted to access inserted objects from an already committed \(cs_typeName(self))." + ) + return entity.cs_toRaw().hasPersistentChangedValues + } /** Returns all pending `DynamicObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called. diff --git a/Sources/From.swift b/Sources/From.swift index e75a1bb..5a9b778 100644 --- a/Sources/From.swift +++ b/Sources/From.swift @@ -140,8 +140,16 @@ public struct From { } internal func applyToFetchRequest(_ fetchRequest: CoreStoreFetchRequest, context: NSManagedObjectContext, applyAffectedStores: Bool = true) throws { - - fetchRequest.entity = context.parentStack!.entityDescription(for: EntityIdentifier(self.entityClass))! + + guard let parentStack = context.parentStack else { + + CoreStore.log( + .warning, + message: "Attempted to perform a fetch but the \(cs_typeName(DataStack.self)) has already been deallocated." + ) + throw CoreStoreError.unknown + } + fetchRequest.entity = parentStack.entityDescription(for: EntityIdentifier(self.entityClass))! guard applyAffectedStores else { return diff --git a/Sources/ListMonitor.swift b/Sources/ListMonitor.swift index 9d8ab88..30f134b 100644 --- a/Sources/ListMonitor.swift +++ b/Sources/ListMonitor.swift @@ -963,8 +963,15 @@ public final class ListMonitor: Hashable { return } - - try! newFetchedResultsController.performFetchFromSpecifiedStores() + do { + + try newFetchedResultsController.performFetchFromSpecifiedStores() + } + catch { + + // DataStack may have been deallocated + return + } self.fetchedResultsControllerDelegate.taskGroup.notify(queue: .main) { self.fetchedResultsControllerDelegate.enabled = false