领域从错误的线程访问

Max*_*xim 18 cocoa objective-c realm ios

我正在使用串行GCD队列来处理领域.Realm accessed from incorrect thread当GCD开始为队列切换线程时,应用程序崩溃,异常.有没有办法使用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++;
    });
}];
Run Code Online (Sandbox Code Playgroud)

jps*_*sim 35

从Realm docs:RLMRealm对象不是线程安全的,不能跨线程共享,因此您必须RLMRealm在每个要读取或写入的thread/dispatch_queue中获取一个实例.

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

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

我也注意到一个AccelerationEvent是通过线程传递的,这也是不允许的.所以这个修改过的代码示例通过NSString线程传递.

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++;
    });
}];
Run Code Online (Sandbox Code Playgroud)

我没有运行此代码来确认它是否有效,所以如果仍然无法解决问题,请告诉我.