2014-09-04 7 views
17

से एक्सेस किया गया है मैं क्षेत्र के साथ काम करने के लिए सीरियल जीसीडी कतार का उपयोग कर रहा हूं। जब GCD कतार के लिए थ्रेड स्विच करना शुरू करता है तो Realm accessed from incorrect thread अपवाद के साथ एप्लिकेशन क्रैश हो जाता है। जीसीडी एपीआई का उपयोग कर धागे के साथ दिए गए दायरे को बांधने का कोई तरीका है?दायरे को गलत धागे

यहाँ एक त्वरित उदाहरण

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

उत्तर

34

From Realm docs है: RLMRealm वस्तुओं सुरक्षित थ्रेड नहीं कर रहे हैं और धागे के बीच साझा नहीं किया जा सकता है, तो आप प्रत्येक थ्रेड/dispatch_queue में एक RLMRealm उदाहरण है, जिसमें आप पढ़ने या लिखने के लिए चाहते हैं चाहिए ।

Also from Realm docs: RLMRealm वस्तुओं रन पाश की एक एकल पुनरावृत्ति के भीतर क्षेत्र द्वारा आंतरिक रूप से कैश नहीं किया जाता है, और इस विधि बुला किसी एकल थ्रेड पर कई बार सामान्य रूप से एक ही 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++; 
    }); 
}]; 

मैंने यह कोड यह पुष्टि करने के लिए नहीं चला है कि यह काम करता है, इसलिए मुझे बताएं कि यह अभी भी समस्या का समाधान नहीं करता है।

+0

धन्यवाद, यह काम किया। – Maxim

+0

@ jpsim जो आपने कहा था, मैंने सोचा था कि केवल आरएलएमआरएलएम थ्रेड-सुरक्षित नहीं है, यह पता चला है कि सभी आरएलएम ऑब्जेक्ट उप-वर्ग उस क्षेत्र से मिले हैं, थ्रेड-सुरक्षित नहीं हैं, – onmyway133

+1

रीयल के दस्तावेज़ से: "आप केवल एक ऑब्जेक्ट का उपयोग कर सकते हैं धागा जो इसे बनाया गया था, और आप सीधे अपने किसी भी स्थायी गुणों के लिए अपने इवार्स तक नहीं पहुंच सकते हैं। " https://realm.io/docs/objc/latest/#models – jpsim

संबंधित मुद्दे