核心数据GCD:将正确的受管对象上下文传递给自定义NSManagedObjects [英] Core Data & GCD: Passing the correct managed object context to custom NSManagedObjects

查看:96
本文介绍了核心数据GCD:将正确的受管对象上下文传递给自定义NSManagedObjects的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我得到运行时错误,这似乎是由于我的错误实现 GCD 结合我的自定义NSManagedObjects。



嵌套在一个 GCD 调用,我使用自定义NSManagedObjects(似乎)有自己的托管对象上下文(= self.managedObjectContext )。



我使用由 UIManagedDocument 提供的托管对象上下文在应用程序委托中创建托管对象上下文: self.managedDocument.managedObjectContext



我不明白如何将正确的托管对象上下文传递到我的自定义NSManagedObjects。



这是我的主要方法(在​​视图控制器中):

  dispatch_queue_t queue; 
queue = dispatch_queue_create(queue,NULL);
dispatch_async(queue,^ {
// ...
NSDecimalNumber * value = [reportedPeriod
valueForCoa:figure.code
convertedTo:self.currencySymbol];
// ...});
}

在这个主方法中,我没有对受管对象上下文的任何引用,我只是调用 valueForCoa:convertedTo:(其编码如下):

   - (NSDecimalNumber *)valueForCoa:(NSString *)coaStr 
convertedTo(NSString *)targetCurrencyStr {
// ...
CoaMap * coa = [CoaMap coaItemForString:coaStr
inManagedObjectContext:self.managedObjectContext];
// ...
}

valueForCoa 是我的自定义子类NSManagedObject ReportedPeriod 中的一个方法,并使用其(默认)托管对象上下文 self.managedObjectContext



应用程序通常在以下方法中在自定义子类NSManagedObject CoaMap 中崩溃执行获取请求:

  +(CoaMap *)coaItemForString:(NSString *)coaStr 
inManagedObjectContext:(NSManagedObjectContext * )context {

NSFetchRequest * request = [NSFetchRequest
fetchRequestWithEntityName:NSStringFromClass([self class])];
NSPredicate * predicate =
[NSPredicate predicateWithFormat:@coa ==%@,coaStr];
request.predicate = predicate;
// **运行时错误发生在下面的行**
NSArray * results = [context executeFetchRequest:request error:nil];
// ...
}

错误消息是:由于未捕获异常NSGenericException而终止应用程序,原因:'*** Collection< __ NSCFSet:0x9a8a4a0>



请帮助我解决这个问题,并给我一些建议,如何提高我的代码通过正确的管理对象上下文(或如何确保在所有方法中使用正确的上下文)?



非常感谢!

解决方案

该错误通常涉及使用受管对象不正确的上下文跨不同线程或队列。你在主队列上创建了MOC,但是你在后台队列中使用它,而不考虑这个事实。在背景队列中使用MOC不是错误,但您需要注意并准备。



您没有说你如何创建MOC。我建议您应该这样做:

  NSManagedObjectContext * context = [[NSManagedObjectContext alloc] 
initWithConcurrencyType:NSMainQueueConcurrencyType];

对于主队列并发,你可以在主线程上正常使用它。当您处于您的分派队列时,请执行以下操作:

  [context performBlockAndWait:^ {
NSFetchRequest * request = [NSFetchRequest
fetchRequestWithEntityName:NSStringFromClass([self class])];
NSPredicate * predicate =
[NSPredicate predicateWithFormat:@coa ==%@,coaStr];
request.predicate = predicate;
NSArray * results = [context executeFetchRequest:request error:nil];
// ...
}];

这将确保MOC的工作发生在主线程上,即使你在后台队列。 (技术上,它实际上意味着MOC的工作在后台将正确地同步它在主队列上的工作,但结果是一样的:这是安全的方式做到这一点)。



一个类似的方法是使用 NSPrivateQueueConcurrencyType 。如果你这样做,你可以使用 performBlock performBlockAndWait 在任何地方为MOC,而不仅仅是在后台线程。 / p>

I get runtime errors which seem to result from my incorrect implementation of GCD in combination with my custom NSManagedObjects.

Nested in a GCD call, I am using custom NSManagedObjects which (seem to) have their own managed object contexts (= self.managedObjectContext).

I am creating the managed object context in the app delegate by using the managed object context provided by UIManagedDocument: self.managedDocument.managedObjectContext.

I don't understand how to pass the correct managed object context down to my custom NSManagedObjects. How would I need to change my code to use the correct managed object context?

This is my main method (inside a view controller):

dispatch_queue_t queue;
queue = dispatch_queue_create("queue", NULL);
dispatch_async(queue, ^{
// ...
NSDecimalNumber *value = [reportedPeriod 
   valueForCoa:figure.code 
   convertedTo:self.currencySymbol];
// ...});
}

In this main method I do not have any reference to a managed object context, I do just call valueForCoa:convertedTo: (which is coded as follows):

- (NSDecimalNumber*)valueForCoa:(NSString*)coaStr
convertedTo:(NSString*)targetCurrencyStr {
// ...
CoaMap *coa = [CoaMap coaItemForString:coaStr
   inManagedObjectContext:self.managedObjectContext];
// ...
}

valueForCoa is a method in my custom subclassed NSManagedObject ReportedPeriod and uses its (default) managed object context self.managedObjectContext.

The app then usually crashes in the custom subclassed NSManagedObject CoaMap in the following method when it executes the fetch request:

+ (CoaMap*)coaItemForString:(NSString*)coaStr 
inManagedObjectContext:(NSManagedObjectContext*)context {

NSFetchRequest *request = [NSFetchRequest 
fetchRequestWithEntityName:NSStringFromClass([self class])];
NSPredicate *predicate = 
   [NSPredicate predicateWithFormat:@"coa == %@",coaStr];
   request.predicate = predicate;
// ** The runtime error occurs in the following line **
NSArray *results = [context executeFetchRequest:request error:nil];
// ...
}

The error message is: Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x9a8a4a0> was mutated while being enumerated.

Could you please help me with this issue and give me some suggestions on how to improve my code to pass the correct managed object contexts (or on how to make sure that the correct context is used in all methods)?

Thank you very much!

解决方案

That error generally relates to using a managed object incorrectly context across different threads or queues. You created the MOC on the main queue, but you're using it on a background queue without considering that fact. It's not wrong to use the MOC on a background queue, but you need to be aware of that and take preparations.

You didn't say how you're creating the MOC. I suggest that you should be doing this:

NSManagedObjectContext *context = [[NSManagedObjectContext alloc]
    initWithConcurrencyType: NSMainQueueConcurrencyType];

With main queue concurrency you can just use it normally on the main thread. When you're in your dispatch queue though, do this:

[context performBlockAndWait:^{
    NSFetchRequest *request = [NSFetchRequest 
        fetchRequestWithEntityName:NSStringFromClass([self class])];
    NSPredicate *predicate = 
       [NSPredicate predicateWithFormat:@"coa == %@",coaStr];
    request.predicate = predicate;
    NSArray *results = [context executeFetchRequest:request error:nil];
    // ...
}];

This will ensure that the MOC's work occurs on the main thread even though you're on a background queue. (Technically what it actually means is that the MOC's work in the background will be correctly synchronized with work it does on the main queue, but the result is the same: this is the safe way to do this).

A similar approach would be to use NSPrivateQueueConcurrencyType instead. If you do that, you'd use performBlock or performBlockAndWait everywhere for the MOC, not just on background threads.

这篇关于核心数据GCD:将正确的受管对象上下文传递给自定义NSManagedObjects的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆