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 Realm
s 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
Pass in a Type to a Generic Swift Extension, or Ideally Infer It
Round Top Corners of a Uiview and Add Border
How to Stop Symbolicate Adding "<Redacted>" Pieces to iOS Crash Log
Swift: Navigate to New Viewcontroller Using Button
Typewriter Effect Text Animation
Error Itms-90086 Submitting App
Nsnotificationcenter Swift 3.0 on Keyboard Show and Hide
Perform a Deeplink from Swiftui Widget on Tap
Exception Type: Exc_Crash (Sigabrt)
How to Use Http Live Streaming Protocol in iPhone Sdk 3.0
Push Notification -Didfinishlaunchingwithoptions
Maximum Number of Peripherals on Corebluetooth
Avfoundation Image Orientation Off by 90 Degrees in the Preview But Fine in Camera Roll
Toggling Airplane Mode in iOS Programmatically
Filetransfer Using Xmppframework in iOS
Create Movie from [Uiimage], Swift
How to Add Particle Effects to an iOS App That Is Not a Game Using iOS 7 Spritekit Particle