私は、レルムを扱うためにシリアルGCDキューを使用しています。 GCDがキューのスレッドの切り替えを開始すると、Realm accessed from incorrect thread
例外でアプリケーションがクラッシュします。 GCD APIを使用して、特定のレルムをスレッドにバインドする方法はありますか?
ここに簡単な例があります
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++;
});
}];
From Realm docs :RLMRealm
オブジェクトはスレッドセーフではなく、スレッド間で共有できないため、読み取りまたは書き込みを行う各スレッド/ dispatch_queueでRLMRealm
インスタンスを取得する必要があります。
Realm docsからも :RLMRealm
オブジェクトはRealmによって内部的にキャッシュされ、実行ループの1回の反復内で1つのスレッドでこのメソッドを複数回呼び出すと、通常は同じRLMRealm
オブジェクトが返されます。
これを知っているので、私はコードサンプルを変更して、それがキャッシュされているため、パフォーマンスが低下することなく、dispatch_async
ブロックからRLMRealm
を直接取得します。
また、AccelerationEvent
がスレッド間で渡されたことにも気付きましたが、これも許可されていません。したがって、この変更されたコードサンプルは、代わりにスレッド全体でNSString
sを渡します。
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++;
});
}];
このコードを実行して動作を確認していないので、問題がまだ解決しない場合はお知らせください。