CoreStore
CoreStore copied to clipboard
[CoreStore: Error] NSManagedObjectContext+Transaction.swift:203 saveAsynchronouslyWithCompletion
I am using ImportUniqueObjects extension to import data from the server. If the Store is empty import works but if there is a previous data, following error comes
⚠️ [CoreStore: Error] NSManagedObjectContext+Transaction.swift:203 saveAsynchronouslyWithCompletion
↪︎ Failed to save 'NSManagedObjectContext'.
(CoreStore.CoreStoreError) .internalError (
.errorDomain = "com.corestore.error";
.errorCode = 4;
.NSError = (
.domain = "NSCocoaErrorDomain";
.code = 1560;
.userInfo = 1 key-value(s) [
"Error Domain=NSCocoaErrorDomain Code=1570 \"The operation couldn\U2019t be completed. (Cocoa error 1570.)\" UserInfo={NSValidationErrorObject=<KargoDetailCD: 0x600000289fb0>
(entity: KargoDetailCD; id: 0xd000000004040002 <x-coredata://8E3ADB60-D46E-466A-91C6-840A45557571/KargoDetailCD/p257> ;
data: {\n date = \"2015-10-13 06:50:00 +0000\";\n
lat = nil;\n location = \"\";\n
long = nil;\n
message = \"Message\";\n
parent = nil;\n
status = 0;\n}),
NSValidationErrorKey=parent, NSLocalizedDescription=The operation couldn\U2019t be completed. (Cocoa error 1570.)}",
I know code 1560 is validation error but why it works in the first time but not the second time puzzles me. Error code also shows that parent is nil.
Here is the relevant models
Storage.stack.perform(asynchronous: { transaction in
try! transaction.importUniqueObjects(Into(KargoCD.self), sourceArray: kargos)
}, success: { done in
print("DoneStore :\(done)")
}, failure: { error in
print("MyError CoreStore: \(error)")
})
class KargoCD: NSManagedObject {
@NSManaged var expected: Date?
@NSManaged var extra: String?
@NSManaged var finishDate: Date?
@NSManaged var isDelivered: NSNumber
@NSManaged var name: String?
@NSManaged var receiver: String?
@NSManaged var sender: String?
@NSManaged var slug: String
@NSManaged var startDate: Date?
@NSManaged var trackingID: String
@NSManaged var trackingNumber: String
@NSManaged var updateDate: Date?
@NSManaged var detail: NSOrderedSet
}
class KargoDetailCD: NSManagedObject {
@NSManaged var message: String?
@NSManaged var date: Date?
@NSManaged var location: String?
@NSManaged var status: NSNumber
@NSManaged var lat: NSNumber?
@NSManaged var long: NSNumber?
@NSManaged var parent: KargoCD
}
extension KargoDetailCD:ImportableObject {
typealias ImportSource = KargoDetail
func didInsert(from source: KargoDetail, in transaction: BaseDataTransaction) throws {
self.message = source.message
self.date = source.date
self.location = source.location
self.status = NSNumber(value: source.status.rawValue)
}
}
extension KargoCD:ImportableUniqueObject {
typealias ImportSource = Kargo
// MARK: ImportableUniqueObject
typealias UniqueIDType = String
static var uniqueIDKeyPath: String {
return #keyPath(KargoCD.trackingID)
}
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool {
return true
}
static func shouldUpdate(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool {
return true
}
static func uniqueID(from source: Kargo, in transaction: BaseDataTransaction) throws -> String? {
return source.trackingID
}
func update(from source: Kargo, in transaction: BaseDataTransaction) throws {
self.name = source.name
self.trackingNumber = source.trackingNumber
self.trackingID = source.trackingID
self.slug = source.slug
self.startDate = source.startDate
self.updateDate = source.updateDate
self.finishDate = source.finishDate
self.expected = source.expectedDate
self.isDelivered = source.isDelivered as NSNumber
self.sender = source.sender
self.receiver = source.receiver
self.extra = source.extra
let details = try transaction.importObjects(Into(KargoDetailCD.self), sourceArray: source.details)
self.detail = NSOrderedSet(array: details)
}
}
@tosbaha If I'm interpreting your error message correctly,
NSValidationErrorObject=<KargoDetailCD: 0x600000289fb0> ... NSValidationErrorKey=parent
I think the issue is that the moment this line is executed,
self.detail = NSOrderedSet(array: details)
the old KargoDetailCD
instances get their KargoDetailCD.parent
set to nil
. You probably have a "required" constraint for the KargoDetailCD.parent
relation.
Either you remove this requirement, or you delete the old details before you assign new ones. I would recommend the latter so your sqlite file don't get polluted with orphaned records.
Thanks a lot! I really appreciate your dedication to this project. I added below code and error is gone.
if let deletable = self.detail.array as? [KargoDetailCD] {
transaction.delete(deletable)
}
PS: It is not related to this question directly, but is there a way to have a Uniqueness by using multiple fields. Because for this user case, I don't have any ID to differentiate. Something like Hashable protocol maybe?