2014-09-04 56 views
17

üzerinden erişilen bölge, bölge ile çalışmak için seri GCD sırasını kullanıyorum. Uygulama, GCD sıra için iş parçacıkları arasında geçiş yapmaya başladığında Realm accessed from incorrect thread istisnasıyla çöküyor. GCD API'yi kullanarak bir thread ile verilen bölgeyi bağlama yolu var mı? İşte Hatalı iş parçacığı

hızlı bir örnek

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

cevap

34

From Realm docs var: Eğer okumak veya yazmak istediğiniz her iplik/dispatch_queue bir RLMRealm örneğini almak gerekir böylece RLMRealm nesneler, iş parçacığı güvenli olmayan ve parçacığı üzerinde paylaşılamaz .

Also from Realm docs : RLMRealm objeler, normal olarak, aynı RLMRealm nesne döndürür çalıştırma döngüsünün tek bir yineleme içinde tek bir iplik üzerinde birden çok kez bölge tarafından dahili olarak önbelleğe ve bu yöntemi aradığınız.

Bunu bildiğimde, kod örneğinizi, önbelleğe alındığı için, bir performans cezası verilmeksizin kullanıldığında, RLMRealm kodunu doğrudan dispatch_async bloğundan almak için değiştirdim.

Ayrıca, bir AccelerationEvent ileti dizisinin geçmesine de izin verildiğini de fark ettim. Bu değiştirilen kod örneği, bunun yerine iş parçacıkları boyunca NSString s geçer.

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

Çalıştığından emin olmak için bu kodu çalıştırmadım, bu sorunun çözülmediğini bana bildirin.

+0

Teşekkürler, işe yaradı. – Maxim

+0

Söylediklerinizden gelen şey, sadece RLMRealm'in iş parçacığı olmadığını düşündüm, tüm RLMObject alt sınıflarının bu alandan aldığının ortaya çıktığı ortaya çıktı. " – onmyway133

+1

" Realm belgelerinden: "yalnızca bir nesneyi oluşturulduğu iş parçacığı ve kalıcı varlıkları için doğrudan kendi ivarlarına erişemezsiniz. " https://realm.io/docs/objc/latest/#models – jpsim

İlgili konular