理解 RealmSwift 中的平等

Ben*_*ard 2 realm swift

我有一些item从 Realm 获取的 s:

let items = realm.objects(ShoppingListItem.self)
print("\(items.count) items") // 10 items
Run Code Online (Sandbox Code Playgroud)

每个item都有一个subdepartment,每个subdepartment都有一个department

let departments = items.flatMap({ $0.product?.subdepartment?.department })
print("\(departments.count) departments") // 10 departments
Run Code Online (Sandbox Code Playgroud)

我的目标是Department从这个列表中找到唯一的对象。预期的结果是 4。我这里的标准方法是使用Set

let uniqueDepartments1 = Set(departments)
print("\(uniqueDepartments1.count) unique departments via Set") // 9 unique departments via Set - but changes every time!?
Run Code Online (Sandbox Code Playgroud)

我想一定有一些与 Realm 对待平等的方式有关的东西。但是为了检查,我还尝试通过枚举获取唯一的部门:

var uniqueDepartments2 = [Department]()
for department in departments {
    if uniqueDepartments2.contains(department) {
        continue
    }
    uniqueDepartments2.append(department)
}
print("\(uniqueDepartments2.count) unique departments via enumeration") // 4 unique departments via enumeration
Run Code Online (Sandbox Code Playgroud)

这确实是预期的结果。

为什么Set在这里不能像我预期的那样工作?为什么每次运行时计数都会改变?

编辑 2/27

以下是正在使用的模型:

class ShoppingListItem: Object {
    dynamic var product: Product?

    convenience init(ingredient: Ingredient) {
        self.init()

        self.product = ingredient.product
    }
}

class Product: Object {
    dynamic var productID, subdepartmentID, title: String?
    dynamic var subdepartment: Subdepartment?
}

class Department: Object {
    dynamic var departmentID, title: String?
}

class Subdepartment: Object {
    dynamic var subdepartmentID, departmentID, title: String?
    dynamic var department: Department?
}
Run Code Online (Sandbox Code Playgroud)

bda*_*ash 5

简而言之:为了使Object子类正确地可散列,您当前必须将属性声明为主键。

Set建立在哈希表之上。这意味着它通过首先计算对象的散列值,将该散列值映射到散列表中的存储桶,然后检查该存储桶中的每个条目是否与指定对象相等来检查特定对象的存在。

这种实现的性质意味着为了Set在给定类型的对象上正确工作,hashValue属性和==运算符都必须遵守特定的规则。特别是,任何两个==返回的对象都true必须从它们的hashValue属性返回相同的值(相反不是必需的;两个不相等的对象具有相同的 是完全有效的hashValue)。除非您的类将属性声明为主键,否则Realm 的hashValue==目前不满足此标准。当没有声明主键时,的默认计算遵循,它只返回对象在内存中的地址。自从ObjecthashValue-[NSObject hash]Object.==允许具有不同地址的两个对象为比较相等,这违反之间的关系hashValue==予上文所述,当用于导致不正确的行为Set,或作为一个关键Dictionary。我已经针对 Realm提交了一个错误,要求==修复行为以与hashValue属性返回的值兼容。