Search code examples
iosswiftcore-datasetnsset

Set doesn't work for NSManagedObject?


I found it recently in my program, the duplications are not stopped, even I used the Set. The object is called Category, with two variables.

import Foundation
import CoreData

extension Category {
    @NSManaged var name: String?
    @NSManaged var items: NSSet?
}
class Category: NSManagedObject {
    override var hashValue: Int {
    return name!.hashValue
    }
}
func == (left: Category, right: Category) -> Bool {
     return left.name == right.name
}

I have override the hashValue: Int and the == method in the class, but the Set still consider them as two objects. Does that mean Set doesn't work for NSManagedObjects or I have something left need to be done?

Here is my unit test code:

    guard let cate1 = NSEntityDescription.insertNewObjectForEntityForName("Category", inManagedObjectContext: context) as? MyProgram.Category else { return }
    cate1.name = "Cate"
    cate1.items = nil
    guard let cate2 = NSEntityDescription.insertNewObjectForEntityForName("Category", inManagedObjectContext: context) as? MyProgram.Category else { return }
    cate2.name = "Cate"
    cate2.items = nil
    let combine = Set<MyProgram.Category>([cate1, cate2])
    assert(cate1.hashValue == cate2.hashValue)
    assert(combine.count == 1)

It will fail at the last line of code. Can anybody who knows the reason gives me some advices?


Solution

  • Unfortunately, what you are trying to do is not possible with Core Data managed objects.

    As a consequence you cannot define your own notion of "equality" for Core Data managed objects in a way that it works with Set or NSSet.

    To check if a set already contains a managed object with a given property you can do something like

    if (combine.contains { $0.name == cate2.name }) {
    
    }
    

    In order to avoid Category objects with the same name, you would have to execute a fetch request which checks if an object with the given name already exists.