I'm having a wired problem with core data. With Swift3 in iOS 10 I get the managed object context each time I am fetching or storing data with
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
In my app I have two entities 'User' and 'Ledger'. I want to assign a ledger to a user, but a user can have multiple ledgers. Therefore, I have a UserTableView where I can display the users and a UserViewController class, where I create a user. The same I have for ledger. When creating a ledger I get also a list of all users from which I select one and which should assigned to the ledger and vice versa.
When saving like aforementioned, I get the error
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for to-one relationship: property = "user"; desired type = User; given type = User;
My data model looks as follows: Data Model
Any help is highly appreciated:)
I had this same problem. In my case it was happening while I was running unit tests. In that case, there were two core data stacks in memory at once, one for the application harness and the other for my running unit tests.
The first clue to solving this was to put an assertion right before setting the relationship property to make sure the entity type of the object I was setting was the same as the expected entity type of the relationship. They should be identical, and in my case they were not.
In my case I had a MatchRequest
that had a one-to-one relationship with Player
called "initiator". So my assertion looked like the following:
let player = try Player.findLocal(for: matchRequest.initiator, in: moc, createIfMissing: true)
let expectedEntity = self.entity.relationshipsByName["initiator"]!.destinationEntity!
assert(player!.entity === expectedEntity, "Player returned doesn't have the same entity type")
self.initiator = player
The above assertion failed, which I suspect is similar to the assertion used by Core Data that causes the argument exception.
When inspecting Player.entity(), it would return the same entity instance that was causing the failure.
I think the root of the problem is that Core Data is setting some static property for entities that will get incorrectly shared across core data stacks. Calling MyManagedObject.entity() will work correctly when called from one stack but not the other.
So, to work around the problem, when I create my Player object to put into the relationship, I get the entity using the older NSEntityDescription.insertNewObject(...)
API, rather than the newer MyManagedObject(context:)
constructor. This ensures that the correct entity is used for the given managed object context.
So, to recap:
// SOMETIMES FAILS if you have more than one core data stack:
result = Player(context: managedObjectContext)
// ALWAYS WORKS:
result = NSEntityDescription.insertNewObject(forEntityName: "Player", into: managedObjectContext) as? Player
I had the same issue, but i was very sure I didn't have 2 Core Data Stacks like the previous answer did.
In the end i realized i had initialized a reference to NSStoreCoordinator
and a view context and background context using the lazy
keyword. I also had a bunch of code doing some heavy lifting in the background thread and saving using said stack.
Apple's docs say: "If a property marked with the lazy modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once."
So, this unfortunate scenario is another way to get to this error. Solution: make sure don't lazy
anything in your Core Data Stack specially when doing lots of background/foreground thread work.
I hope it helps someone in the future. To you future developer, if you are here: Good luck.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With