Closed rusik closed 8 years ago
Note: realms have default configuraton except file path
Hmm, as i can see, you are caching realms with weak reference, so if it not referencing with strong anywhere in user's code it creates every time. For my objects i create realms dynamically with realmWithConfiguration
and don't store this realms with strong reference. So realm for TrickProgress creates for every cellForRowAtIndexPath
call. This is the cause of bad performance.
But is it a good idea to cache realms with weak? Maybe it should be strong? Becuase otherwise this is not very usefull if i should store strong reference to realm at the same time in my code.
I think your cachng strategy looks a little bit strange (and not very useful):
realmWithConfiguration
will return the first created object) — is it a core limitation?realmWithConfiguration
but it's not working without strong references in my code)1) I can't create two different objects of RLMRealm for the same thread (because the second
realmWithConfiguration
will return the first created object) — is it a core limitation?
That's not the case. You can have multiple different objects of RLMRealm on the same thread. Realms are cached by their path.
2) Cache work only if i already have strong reference to RLRealm object in my code (what in fact is a cache on my side, not yours)
Yup, that's intentional. Otherwise you would have no chance to close a Realm, which is in some cases necessary. It's your responsibility to hold it as long as you want to have access to it.
3) If i don't want to recreate RLMRealm objects every time for different threads i should implement my custom logic to store them with strong references (but you already have this logic in
realmWithConfiguration
but it's not working without strong references in my code)
That's right. It would be already sufficient in your case, if you store the realm in a property of your view controller. This shouldn't hurt or disturb to much.
1) That's not the case. You can have multiple different objects of RLMRealm on the same thread. Realms are cached by their path.
Yeah, I said a little bit incorrect. So I can't create two different objects of RLMRealm for the same path on the same thread, why this limitation is exist?
2) Yup, that's intentional. Otherwise you would have no chance to close a Realm, which is in some cases necessary. It's your responsibility to hold it as long as you want to have access to it.
As i see there is no public method to close a realm.
3) That's right. It would be already sufficient in your case, if you store the realm in a property of your view controller. This shouldn't hurt or disturb to much.
I can't see any useful cases for this type of caching RLMRealm objects by realm. As for me it is creating more misunderstading than benefits.
Yeah, I said a little bit incorrect. So I can't create two different objects of RLMRealm for the same path on the same thread, why this limitation is exist?
There are not too many valid cases, I can come up where it would make sense to allow accessing the same realm with different configurations and there would be some problems you can easily hit, if we would allow that (different schema (/versions)). If you have anything in mind where it restricts you currently, please explain how and why.
I can't see any useful cases for this type of caching RLMRealm objects by realm. As for me it is creating more misunderstading than benefits.
It's a significant performance improvement and workaround for limitations of the supported platforms. Without that you can easily run out of mapped memory regions.
Okey, I have a case for you.
I have two realm files in documents folder. One is completely empty Empty.realm
and another one has some data Data.realm
. I have this code:
#define FileInDocuments(file) [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:file]
[[NSFileManager defaultManager] copyItemAtPath:FileInDocuments(@"Empty.realm")
toPath:FileInDocuments(@"Current.realm")
error:nil];
RLMRealm *realm = [RLMRealm realmWithPath:FileInDocuments(@"Current.realm")];
NSLog(@"%d", realm.isEmpty); // 1 — this is correct
[[NSFileManager defaultManager] removeItemAtPath:FileInDocuments(@"Current.realm") error:nil];
[[NSFileManager defaultManager] copyItemAtPath:FileInDocuments(@"Data.realm")
toPath:FileInDocuments(@"Current.realm")
error:nil];
realm = [RLMRealm realmWithPath:FileInDocuments(@"Current.realm")];
NSLog(@"%d", realm.isEmpty); // 1 — for this time this is not correct
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
RLMRealm *realm2 = [RLMRealm realmWithPath:FileInDocuments(@"Current.realm")];
NSLog(@"%d", realm2.isEmpty); // 0 — this is correct
}];
So as you can see first i've opened an empty file, then replaced it with file with data, but realmWithPath:
returned to me a cached RLMRealm object referencing an old empty file.
How can i avoid or fix this issue without knowing the internal structure of realmWithConfiguration:
method with it caching strategy?
This is just one strange case with caching but I think it can be much more.
How can i avoid or fix this issue without knowing the internal structure of realmWithConfiguration: method with it caching strategy?
You should always close a Realm file by not retaining anymore any accessor to it, before making modifications to the file on disk.
For your fix I'd recommend using a dedicated autoreleasepool like seen below:
@autoreleasepool {
RLMRealm *realm = [RLMRealm realmWithPath:FileInDocuments(@"Current.realm")];
NSLog(@"%d", realm.isEmpty); // 1 — this is correct
}
I'm closing this issue as @mrackwitz's suggestion is correct. @Rusik please let us know if there's anything more we can do to help you!
The OP noted that doing realmWithConfiguration
is slow, but thats the way how the default realm is implemented
+ (instancetype)defaultRealm {
return [RLMRealm realmWithConfiguration:[RLMRealmConfiguration rawDefaultConfiguration] error:nil];
}
does this mean that using the provided defaultRealm is a slowdown?
No, the default Realm helper is not any slower than the configuration-based initializer (or any other initializer). However, the first initialization of a Realm will always be slower than subsequent inits because the file has to be mmapped initially, whereas that doesn't need to be done afterwards.
No, the default Realm helper is not any slower than the configuration-based initializer (or any other initializer).
Thats exactly what i mean, if the configuration-based initializer is slow, than the default Realm helper is slow... and the OP indicated, that the configuration-based initializer is slow, while calling it multiple times in a loop
Not sure what your question is. "if the configuration-based initializer is slow", what does slow mean in your context? Slower than what? There's no alternative initializer that will be faster...
well, it is not explicitly clear that when calling defaultRealm a new realm is constructed each time when calling defaultRealm, so the user would expect the performance of a reference retrieval, not the performance of object construction
it is not explicitly clear that when calling defaultRealm a new realm is constructed each time when calling defaultRealm
That is not generally the case. The file mapping is only unloaded if all in-memory references to the Realm are entirely freed.
I have data structure like this:
I have table view with data source like this:
The question is: If I store Trick and TrickProgress entities in the same realm the performance is really great, but if i store them in the different realms (what I want to do) the performance is so bad (even on iPhone 6s) so I can't scroll table view without visible lagging. Yeah, maybe this is not so great idea to fetch entity from database in the
cellForRow
, but the question is why this is such a big difference in performance?