Saren Inden
Saren Inden

Reputation: 3660

Coredata get managed object while a other instance of the object is being edit leads to crash

My app (target iOS 6 and higher) has a dashboard view a Activity table view and a Activity details view (a lot more but they are irrelevant for this subject).

Once the user comes on the dashboard I run an update for the activities. During this I get a list of Activities from Core data to update if needed. If i open the table view when the updating is done, everything is fine. But when i open it during the update the app crashes. (In the tableview i load a list of the activities from core data (the same objects).

The error is: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'The left hand side for an ALL or ANY operator must be either an NSArray or an NSSet.'

Well I think this error is wrong in what it says because the statement works fine when i'm not updating

The fetchrequest:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Activity" inManagedObjectContext:managedObjectContext]];
[fetchRequest setRelationshipKeyPathsForPrefetching:@[@"followedPlayer"]];
[fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"calendarDate" ascending:YES], [NSSortDescriptor sortDescriptorWithKey:@"startTime" ascending:YES]]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"ANY typeOfActivity IN %@", array]];

Personally I think the problem is that I have two instances of one Activity while one is being edited and save has not yet been called on the managedobjectcontext (the managedobjectcontext is a singleton). Then when save is called (or when the second object is created while the first object has unsaved changes) the app crashes.

I think this problem could be solved by creating a singleton class with an array of the activities so that there is only one instance of the activity object at all times (or just block access to the tableview while updating). But I wonder if this could be done in a nicer way.

The way I have in mind is to get a read only/unmanaged object from core data. This could be done by accessing the sqlite database directly. But in the detail view I have to get other objects that have an relationship with the activity so that is not really the way to go i think.

Does anyone now if it is possible (and how) to get a read only managed object or something like that without direct accessing the sqlite database or should i just go for a class that contains the activities so i don't get duplicates?

Kind regards

Saren Inden

Upvotes: 1

Views: 281

Answers (1)

borrrden
borrrden

Reputation: 33421

Core Data is not thread safe. You should expect lots of trouble like this if you share an NSManagedObjectContext or even an NSManagedObject between threads. For some further reading, check out Concurrency with Core Data.

Also starting in iOS 5.0, you can set the concurrencyType of an NSManagedObjectContext. There are three types. With the queue based types, you need to make sure everything you do with Core Data is via the performBlock: and performBlockAndWait: methods. I got burned by forgetting several times (it will often manifest via deadlocks).

Upvotes: 1

Related Questions