iOS – core data and GCD: Pass the correct host context to custom NSManageDObjects

I get a runtime error, which seems to be due to my wrong implementation of GCD combined with my custom NSManagedObjects.

Nested in GCD call In, I use custom NSManagedObjects (it seems) to have my own managed object context (= self.managedObjectContext).

I create a 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 to my custom NSManagedObjects. How can I change the code to use the correct managed object context?

This is my main method (in the 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 don’t have any reference to the context of the managed object, I just call valueForCoa: convertedTo :(The encoding is as follows):

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

valueForCoa is A method in my custom subclass NSManagedObject ReportedPeriod, and use its (default) managed object context self.managedObjectContext.

Then, when executing the get request, the application usually will be in the following method Crash in custom subclass NSManagedObject CoaMap:

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

NSFetchRequest *request = [NSFetchRequest < br />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: the application was terminated due to the uncaught exception’NSGenericException’, reason:’*** Collection< __ NSCFSet: 0x9a8a4a0> was mutated when enumerated.

Can you help me solve this problem and give some suggestions on how to improve my code to pass the correct managed object context (or how to ensure that the correct context is used in all methods)?

Thank you very much!

This error usually involves using managed object error context across different threads or queues. You are on the main queue MOC is created, but you use it in the background queue without considering the fact. There is nothing wrong with using MOC on the background queue, but you need to understand this and be prepared.

You Did not say how you created the MOC. I suggest you should do this:

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

pre>

Using the main queue concurrency, you can use it normally on the main thread. When you are in the dispatch queue, please do the following:

[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 even if you are in the background queue, MOC's work will be performed on the main thread. (Technically speaking, it actually means that MOC's work in the background will be the same as it on the main queue. Works correctly synchronized, but the result is the same: this is the safe method).

A similar method is to use NSPrivateQueueConcurrencyType. If you do this, you can use performBlock or perf for MOC anywhere ormBlockAndWait, not just on a background thread.

I get runtime errors, which seems to be due to my wrong implementation of GCD combined with my custom NSManagedObjects.

Nested in the GCD call, I use custom NSManagedObjects (seems) to have its own managed object context (= self.managedObjectContext).

I provide it by using UIManagedDocument The managed object context creates the managed object context in the app delegate: self.managedDocument.managedObjectContext.

I don’t understand how to pass the correct managed object context to my custom NSManagedObjects. How can I change the code to use The correct managed object context?

This is my main method (in the 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 don’t have any reference to the context of the managed object, I just call valueForCoa: convertedTo :(The encoding is as follows):

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

valueForCoa is A method in my custom subclass NSManagedObject ReportedPeriod, and use its (default) managed object context self.managedObjectContext.

Then, when executing the get request, the application usually will be in the following method Crash in custom subclass NSManagedObject CoaMap:

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

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

The error message is: The application was terminated due to the uncaught exception'NSGenericException', reason:'*** Collection< __ NSCFSet: 0x9a8a4a0> was mutated when enumerated.

Can you help me solve this problem and give some suggestions on how to improve my code to pass the correct managed object context (or how to ensure that the correct context is used in all methods)?

Thank you very much!

The error usually involves the use of managed object error context across different threads or queues. You created the MOC on the main queue, but you use it in the background queue Regardless of the fact. There is nothing wrong with using MOC on the background queue, but you need to understand this and be prepared.

You did not say how you created the MOC. I suggest you It should do this:

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

Use the main queue for concurrency, you can Use it normally on the main thread. When you are in the dispatch queue, do the following:

[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 even if you In the background queue, the work of the MOC will also be performed on the main thread. (Technically speaking, it actually means that the work of the MOC in the background will be correctly synchronized with its work on the main queue, but the result is the same: this Is a safe method).

A similar method is to use NSPrivateQueueConcurrencyType. If you do this, you can use performBlock or performBlockAndWait for MOC anywhere, not just on a background thread.

Leave a Comment

Your email address will not be published.