Testing for Equality in Realm

Testing for equality in Realm

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

Understanding equality in RealmSwift

In short: in order for an Object subclass to be correctly hashable you must currently declare a property as the primary key.

Set is built on top of a hash table. This means it checks for the existence of a specific object by first computing the hash value of the object, mapping that hash value to a bucket within the hash table, and then checking each entry in that bucket for equality with the specified object.

The nature of this implementation means that for Set to work correctly on objects of a given type, both the hashValue property and == operator must obey specific rules. In particular, any two objects for which == returns true must return the same value from their hashValue property (the reverse is not required; it's completely valid for two unequal objects to have the same hashValue). Realm's implementation's of hashValue and == don't currently meet this criteria unless your class declares a property as the primary key. When no primary key is declared, Object's default hashValue calculation defers to -[NSObject hash], which simply returns the object's address in memory. Since Object.== allows two objects with different addresses to compare equal, this violates the relationship between hashValue and == I outlined above, leading to incorrect behavior when used with Set or as the key of a Dictionary. I've filed a bug against Realm requesting that the behavior of == be fixed to be compatible with the value returned by the hashValue property.

Comparing Objects Realm Swift

Realm objects already conform to Equatable and Hashable since they are subclasses of NSObject. The only thing you need to do is override the isEqual method:

import UIKit
import RealmSwift

class ObjectClass: Object {

@objc dynamic var order = 0
@objc dynamic var number = ""
@objc dynamic var temp = 0
@objc dynamic var state = 1

override func isEqual(_ object: Any?) -> Bool {
if let object = object as? ObjectClass {
return self.order == object.order && self.number == object.number
&& self.temp == object.temp && self.state == object.state
} else {
return false
}
}
}

Querying for a matching array property in Realm

Each Realm model class inheriting from Object conforms to the Equatable protocol by default due to the fact that Object inherits from NSObject, which conforms to Equatable. If the elements of a List conform to the Equatable protocol, the List itself conforms to it as well.

Hence, you should be able to compare List<Product> instances by using the == function and you can also directly compare Shelf objects.

However, be aware that Realm overrides the == function, see Realm object's Equatable is implementation.

If you want a custom comparison, you can override the == function yourself.

Edit: I don't think this can be done using Realms filter method. However, if you don't mind getting an Array back as a result and not a Result collection, the below method can help you.

let searchedProducts = List([product1, product2, product3])  //these are Product instances
let results = Array(realm.objects(Shelf.self)).filter{
if $0.products.count != searchedProducts.count {
return false
}
for product in $0.products {
if searchedProducts.index(of: product) == nil {
return false
}
}
return true
}

The above code has been tested in Playground with a similar class and returned correct results.

Is there any way I can make my function for testing the equality of strings even faster?

Your first function just do not work and is wrong.

You do not the correct parameter types. Do not use register as it has no effect at all. Register is ignored at any level of optimization. Compilers are better than me or you in micro optimizations - so help the compiler optimizer with the const and restrict when applicable.

The second one can be simplified.

int stringsequal1(const char *restrict s1, const char *restrict s2)
{
do
{
if(*s1 != *s2) return 0;
}
while(*s1++ + *s2++);
return 1;
}

and thew result code for both is:

int stringsequal1(const char *s1, const char *s2)
{
do
{
if(*s1 != *s2) return 0;
}
while(*s1++ + *s2++);
return 1;
}

stringsequal1:
xor edx, edx
jmp .L11
.L15:
add rdx, 1
add eax, eax
je .L14
.L11:
movsx eax, BYTE PTR [rdi+rdx]
cmp al, BYTE PTR [rsi+rdx]
je .L15
mov eax, 1
ret
.L14:
ret

int stringsequal2(register char *s1, register char *s2)
{
while(1)
{
if(!((*s1 + *s2) ^ 0)) return 1;
if(*(s1 ++) ^ *(s2 ++)) break;
}
return 0;
}

stringsequal2:
xor eax, eax
jmp .L18
.L22:
add rax, 1
cmp cl, r9b
jne .L21
.L18:
movsx r8d, BYTE PTR [rdi+rax]
movsx r9d, BYTE PTR [rsi+rax]
mov ecx, r8d
add r8d, r9d
jne .L22
mov eax, 1
ret
.L21:
xor eax, eax
ret


Related Topics



Leave a reply



Submit