There's a bug with Core Data such that if you have two entities, A and B, with a one-to-one relationship between them, that relationship will not be setup properly. This bug doesn't care wether you do your work in Objective-C or Swift or both.

The steps to reproduce are as follows:

  • Create two entities, one A and one B.
  • Give each a property, such as name.
  • Add a one-to-one relationship between the two.
  • Generate the class file for each by any method you wish. Doesn't matter which.
  • In your app, create an instance of each and link them by their relationship property.
        let context = persistentContainer.viewContext

        let a = A(context: context)
        a.name = "I'm alive"
        let b = B(context: context)
        b.name = "I'm also alive"
        a.thing = b

        try! context.save()
  • Fetch all A entities and print out their B's. Do the same the other away around too.
        let context = container.viewContext

        let request = A.fetchRequest() as NSFetchRequest<A>
        let allA = try! context.fetch(request)
        print(allA.map({ $0.thing?.name }))
        let bRequest = B.fetchRequest() as NSFetchRequest<B>
        let allB = try! context.fetch(bRequest)
        print(allB.map({ $0.otherThing?.name }))
  • Notice how nothing is nil, as you'd expect, in the console output. This is what we expect.
  • Every time you run this code, you'll see more items in the output.
  • To prevent all these extra duplicates, let's give them a unique constraint, to both the A and B entities. For this to work, you'll also need to change the merge policy of the context.
context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump  
  • Now, notice how it's broken. Your entity properties will show as nil even though we know it should work just fine. This is the bug!
  • To make things work again, remove the unique constraint on B. Now everything works just fine. Tada!

There's an example project displaying this bug on github.