领域从不正确的线程访问 [英] Realm accessed from incorrect thread

查看:187
本文介绍了领域从不正确的线程访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用串行GCD队列与领域工作。应用程序崩溃与 Realm从不正确的线程访问异常时,GCD开始切换队列的线程。有什么方法可以使用GCD API绑定指定领域与线程?

I'm using serial GCD queue to work with realm. Application crashes with Realm accessed from incorrect thread exception when GCD starts to switch threads for the queue. Is there any way to bind given realm with a thread using 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++;
    });
}];


推荐答案

从Realm文档 RLMRealm 对象不是线程安全的,因此您必须在每个想要读取或写入的线程/ dispatch_queue中获得 RLMRealm 实例。

From Realm docs: RLMRealm objects are not thread safe and cannot be shared across threads, so you must get an RLMRealm instance in each thread/dispatch_queue in which you want to read or write.

< a href =http://realm.io/docs/cocoa/0.84.0/api/Classes/RLMRealm.html#//api/name/defaultRealm>也来自Realm文档: RLMRealm 对象由Realm在内部缓存,并且在运行循环的单个迭代中的单个线程上多次调用此方法通常会返回相同的 RLMRealm object。

Also from Realm docs: RLMRealm objects are cached internally by Realm, and calling this method multiple times on a single thread within a single iteration of the run loop will normally return the same RLMRealm object.

所以知道这一点,我修改你的代码示例,直接从 RLMRealm dispatch_async 阻止它被使用,不会导致性能损失,因为它被缓存。

So knowing this, I modified your code sample to get the RLMRealm directly from the dispatch_async block where it is used, without incurring a performance penalty, since it is cached.

AccelerationEvent 通过线程传递,这也是不允许的。因此,这个修改后的代码示例通过线程传递 NSString

I also noticed that an AccelerationEvent was passed across threads, which is also not allowed. So this modified code sample passes NSStrings across threads instead.

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++;
    });
}];

我没有运行此代码来确认它的工作,所以让我知道如果这仍然无法解决问题。

I haven't run this code to confirm that it works, so let me know if this still doesn't resolve the issue.

这篇关于领域从不正确的线程访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆