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
Realm accessed from incorrect thread
提问by Maxim
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?
我正在使用串行 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: 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.
来自 Realm 文档:RLMRealm
对象不是线程安全的,不能跨线程共享,因此您必须RLMRealm
在每个要读取或写入的线程/dispatch_queue 中获取一个实例。
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.
同样来自 Realm 文档:RLMRealm
对象由 Realm 在内部缓存,并且在运行循环的单次迭代中的单个线程上多次调用此方法通常会返回相同的RLMRealm
对象。
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.
因此,知道这一点后,我修改了您的代码示例以RLMRealm
直接从dispatch_async
使用它的块中获取,而不会导致性能损失,因为它已被缓存。
I also noticed that an AccelerationEvent
was passed across threads, which is also not allowed. So this modified code sample passes NSString
s 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.
我还没有运行此代码来确认它是否有效,所以如果这仍然不能解决问题,请告诉我。