ios 从错误的线程访问的领域

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25661023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:12:31  来源:igfitidea点击:

Realm accessed from incorrect thread

iosobjective-ccocoarealm

提问by Maxim

I'm using serial GCD queue to work with realm. Application crashes with Realm accessed from incorrect threadexception when GCD starts to switch threads for the queue. Is there any way to bind given realm with a thread using GCD API?

我正在使用串行 GCD 队列来处理领域。Realm accessed from incorrect thread当 GCD 开始为队列切换线程时,应用程序崩溃并出现异常。有没有办法使用 GCD API 将给定的领域与线程绑定?

Here's a quick example

这是一个快速示例

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

回答by jpsim

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

来自 Realm 文档RLMRealm对象不是线程安全的,不能跨线程共享,因此您必须RLMRealm在每个要读取或写入的线程/dispatch_queue 中获取一个实例。

Also from Realm docs: RLMRealmobjects 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 RLMRealmobject.

同样来自 Realm 文档RLMRealm对象由 Realm 在内部缓存,并且在运行循环的单次迭代中的单个线程上多次调用此方法通常会返回相同的RLMRealm对象。

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

因此,知道这一点后,我修改了您的代码示例以RLMRealm直接从dispatch_async使用它的块中获取,而不会导致性能损失,因为它已被缓存。

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

我还注意到 anAccelerationEvent是跨线程传递的,这也是不允许的。因此,此修改后的代码示例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++;
    });
}];

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

我还没有运行此代码来确认它是否有效,所以如果这仍然不能解决问题,请告诉我。