Reputation: 11201
I have a model class that uses Realm to perform CRUD operations.
I am trying to perform all my operations on a serial queue.
I have declared the queue property:
@property (nonatomic, strong) dispatch_queue_t realmQueue;
@property (strong,nonatomic) RLMRealm *secureRealm;
and I used singleton to initialize the queue:
+ (id)sharedInstance {
static ActivityManager *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[self alloc] init];
});
return sharedManager;
}
-(id)init{
self.realmQueue = dispatch_queue_create("realm_activity", DISPATCH_QUEUE_SERIAL);
dispatch_async(self.realmQueue, ^{
_secureRealm = [RLMRealm defaultRealm];
});
return self;
}
-(NSArray *)getDataOnSettingFilter{
NSMutableArray *activityArr = [NSMutableArray array];
NSString *filterSQL = //;
RLMResults *activityResults = [[[self getActivitySource]activities] objectsWhere:filterSQL];
dispatch_async(self.realmQueue, ^{
[_secureRealm beginWriteTransaction];
for (RealmActivity *activity in activityResults){
//modify realm properties
[_secureRealm addOrUpdateObject:activity];
[activityArr addObject:activity];
}
[_secureRealm commitWriteTransaction];
});
return [activityArr copy];
}
and when I call the above method using:
[[ActivityManager sharedInstance]getDataOnSettingFilter]
I get a crash saying realm is accessed from a incorrect thread.
What am I doing wrong here. How can I check if I am calling the realm on correct thread always ?
Upvotes: 0
Views: 654
Reputation: 54706
You shouldn't store a reference to a singleton Realm
instance, since you cannot ensure that you will always access it from the same thread. As the Realm
documentation states,
Instances of RLMRealm, RLMResults, or RLMArray, or managed instances of RLMObject are thread-confined, meaning that they can only be used on the thread on which they were created, otherwise an exception is thrown
meaning that you should never try to use RLMRealm *realm = [RLMRealm defaultRealm];
to create a singleton Realm
instance and than try to access that everywhere from your app.
You could try using RLMThreadSafeReference
to create references to Realm
objects that can be safely shared between threads, but as the Passing instances across threads part of the documentation states, these references can only be used once, so they can't be reused as a singleton.
However, there is no need for such thing, since every time you call RLMRealm *realm = [RLMRealm defaultRealm];
, the framework automatically creates a reference to your currently used Realm
on the thread you are on enabling you to safely interact with it as long as you don't leave that thread.
The best way to use Realm
in a thread-safe way is to create a new reference to your Realm
using RLMRealm *realm = [RLMRealm defaultRealm];
every time you move between threads and need to access your Realm
. This way you can ensure that you will never get the incorrect thread exception.
Upvotes: 3