理解RealmSwift中的相等性

时间:2017-02-26 20:17:03

标签: swift realm

我有一些item来自Realm:

let items = realm.objects(ShoppingListItem.self)
print("\(items.count) items") // 10 items

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

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

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

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

我认为必须有一些与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

这确实是预期的结果。

为什么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?
}

1 个答案:

答案 0 :(得分:3)

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

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

此实现的本质意味着,Set能够在给定类型的对象上正常工作,hashValue属性和==运算符都必须遵守特定规则。特别是,==返回true的任何两个对象必须从其hashValue属性返回相同的值(反之则不是必需的;它对两个不相等的对象完全有效拥有相同的hashValue)。 hashValue==境界的实施目前不符合此条件,除非您的类声明属性为主键。如果未声明主键,Object的默认hashValue计算将推迟到-[NSObject hash],这只会返回内存中对象的地址。由于Object.==允许两个具有不同地址的对象进行比较,因此违反了上面列出的hashValue==之间的关系,导致与Set一起使用时出现错误行为或Dictionary的关键。我已提交bug against Realm,请求修复==的行为以与hashValue属性返回的值兼容。