I\'m trying to test for equality among Realm
objects in unit tests. However, I\'m unable to get objects to return true
for their equality.
Katsumi from Realm here. Realm object's Equatable
is implemented as follows:
BOOL RLMObjectBaseAreEqual(RLMObjectBase *o1, RLMObjectBase *o2) {
// if not the correct types throw
if ((o1 && ![o1 isKindOfClass:RLMObjectBase.class]) || (o2 && ![o2 isKindOfClass:RLMObjectBase.class])) {
@throw RLMException(@"Can only compare objects of class RLMObjectBase");
}
// if identical object (or both are nil)
if (o1 == o2) {
return YES;
}
// if one is nil
if (o1 == nil || o2 == nil) {
return NO;
}
// if not in realm or differing realms
if (o1->_realm == nil || o1->_realm != o2->_realm) {
return NO;
}
// if either are detached
if (!o1->_row.is_attached() || !o2->_row.is_attached()) {
return NO;
}
// if table and index are the same
return o1->_row.get_table() == o2->_row.get_table()
&& o1->_row.get_index() == o2->_row.get_index();
}
In summary, a) if both objects are unmanaged, it works same as normal object's Equatable
. b) if both objects are managed, if they are the same table (class) and index, they are equal. c) If one is managed, another is unmanaged, ther are not equal.
"managed" means the object has stored in Realm.
So a
and b
in your code is not equal. Because a
and b
are unmanaged (have not stored in Realm) and they are different objects.
let a = Blurb()
a.text = "asdf"
let b = Blurb()
b.text = "asdf"
XCTAssertEqual(a.text, b.text)
Furthermore, when testing the equality, Realm doesn't care the values of the objects. Realm checks only a table and row index (as mentioned "b)"). Because different objects that has the same value are stored in the database is normal.
An example that two objects are equal is like the following:
let a = Blurb()
a.text = "asdf"
let realm = try! Realm()
try! realm.write {
realm.add(a)
}
let b = realm.objects(Blurb.self).first!
print(a == b) // true
Do you know how comparison protocols works on iOS?
If you don't, check here http://nshipster.com/swift-comparison-protocols/
Basically if you do
let a = NSObject()
let b = NSObject()
let c = a
a == b // false
a == c // true
You should create a class like this conform to Equatable
class MyClass: Equatable {
let myProperty: String
init(s: String) {
myProperty = s
}
}
func ==(lhs: MyClass, rhs: MyClass) -> Bool {
return lhs.myProperty == rhs.myProperty
}
let myClass1 = MyClass(s: "Hello")
let myClass2 = MyClass(s: "Hello")
myClass1 == myClass2 // true
myClass1 != myClass2 // false
myClass1 === myClass2 // false
myClass1 !== myClass2 // true
I suggest to check .text for testing
func testRealmEquality() {
let a = Blurb()
a.text = "asdf"
let b = Blurb()
b.text = "asdf"
XCTAssertEqual(a.text, b.text)
}