J'utilise la file d'attente GCD série pour travailler avec le domaine. L'application se bloque avec Realm accessed from incorrect thread
exception lorsque GCD commence à changer de threads pour la file d'attente. Existe-t-il un moyen de lier un domaine donné à un thread à l'aide de l'API GCD?
Voici un exemple rapide
self.realmQueue = dispatch_queue_create("db", DISPATCH_QUEUE_SERIAL);
__block RLMRealm *realm = nil;
dispatch_async(self.realmQueue, ^{
realm = [RLMRealm realmWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"temp"]];
});
self.motionManager = [[CMMotionManager alloc] init];
self.motionManager.accelerometerUpdateInterval = 0.001;
__block int i = 0;
__block BOOL shouldBeginWriteTransaction = YES;
[self.motionManager startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
dispatch_async(self.realmQueue, ^{
if (shouldBeginWriteTransaction) {
[realm beginWriteTransaction];
shouldBeginWriteTransaction = NO;
}
AccelerationEvent *event = [[AccelerationEvent alloc] init];
event.x = accelerometerData.acceleration.x;
event.y = accelerometerData.acceleration.x;
event.z = accelerometerData.acceleration.y;
event.time = [NSDate date];
[realm addObject:event];
if (i % 1000) {
dispatch_async(dispatch_get_main_queue(), ^{
self.xLabel.text = [NSString stringWithFormat:@"%f", event.x];
self.yLabel.text = [NSString stringWithFormat:@"%f", event.y];
self.zLabel.text = [NSString stringWithFormat:@"%f", event.z];
});
}
if (i % 10000 == 0) {
NSDate *startDate = [NSDate date];
[realm commitWriteTransaction];
NSLog(@"save time: %f", [[NSDate date] timeIntervalSinceDate:startDate]);
shouldBeginWriteTransaction = YES;
}
i++;
});
}];
De Realm docs : RLMRealm
les objets ne sont pas thread-safe et ne peuvent pas être partagés entre les threads, vous devez donc obtenir une instance RLMRealm
dans chaque thread/dispatch_queue dans lequel vous voulez lire ou écrire.
également à partir des documents Realm : RLMRealm
les objets sont mis en cache en interne par Realm, et appeler cette méthode plusieurs fois sur un seul thread dans une seule itération de la boucle d'exécution retournera normalement le même RLMRealm
objet.
Donc, sachant cela, j'ai modifié votre exemple de code pour obtenir le RLMRealm
directement à partir du dispatch_async
bloquer où il est utilisé, sans encourir de pénalité de performance, car il est mis en cache.
J'ai également remarqué qu'un AccelerationEvent
était passé entre les threads, ce qui n'est pas non plus autorisé. Ainsi, cet exemple de code modifié passe à la place NSString
s à travers les threads.
self.realmQueue = dispatch_queue_create("db", DISPATCH_QUEUE_SERIAL);
self.motionManager = [[CMMotionManager alloc] init];
self.motionManager.accelerometerUpdateInterval = 0.001;
__block int i = 0;
__block BOOL shouldBeginWriteTransaction = YES;
[self.motionManager startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
dispatch_async(self.realmQueue, ^{
RLMRealm *realm = [RLMRealm realmWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"temp"]];
if (shouldBeginWriteTransaction) {
[realm beginWriteTransaction];
shouldBeginWriteTransaction = NO;
}
AccelerationEvent *event = [[AccelerationEvent alloc] init];
event.x = accelerometerData.acceleration.x;
event.y = accelerometerData.acceleration.x;
event.z = accelerometerData.acceleration.y;
event.time = [NSDate date];
[realm addObject:event];
if (i % 1000) {
NSString *xString = [NSString stringWithFormat:@"%f", event.x];
NSString *yString = [NSString stringWithFormat:@"%f", event.y];
NSString *zString = [NSString stringWithFormat:@"%f", event.z];
dispatch_async(dispatch_get_main_queue(), ^{
self.xLabel.text = xString;
self.yLabel.text = yString;
self.zLabel.text = zString;
});
}
if (i % 10000 == 0) {
NSDate *startDate = [NSDate date];
[realm commitWriteTransaction];
NSLog(@"save time: %f", [[NSDate date] timeIntervalSinceDate:startDate]);
shouldBeginWriteTransaction = YES;
}
i++;
});
}];
Je n'ai pas exécuté ce code pour confirmer qu'il fonctionne, alors faites-moi savoir si cela ne résout toujours pas le problème.