Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data inconsistency - fetch sometimes returns nothing

I've already spent few hours on that one and I can't seem to find a solution. First, some specifications of what do I have:

  • Objective-C iOS 6 app with Core Data
  • Core Data is initialized from UIManagedDocument, which has auto-saving turned on
  • ManagedContext from UIManagedDocument is stored in a static variable and reused throughout the app
  • The app uses RestKit and I utilize ActiveRecord category that it provides.

I have a model with Team entity. In the app, there is a Team List view controller, which loads the teams from the backend. The backend returns JSON array, containing among others, team ID. I store this ID in "id" field in my model, and while iterating over the server response, I lookup if the team for given ID already exists. If it does, I only update its information and pass the object along, if not - I create it first.

And this is where it turns bizarre. This works 90% of time. I can load up the Team List controller, go further in the app, go back to the controller (which loads the data again) and it everything's ok most of the time. Once in a while however, my fetch request will return nothing. As in:

NSArray *results = [context executeFetchRequest:request error:&error];

will return empty array, and the error is also empty. Nothing on the server is ever changing. The request, when I try to debug it, looks as follows:

<NSFetchRequest: 0x127a0e20> (entity: Team; predicate: (id == "123"); sortDescriptors: ((null)); limit: 1; type: NSManagedObjectResultType; )

When I preview the sqlite store in an external app, I can see that the Team item for this ID is present, and in other 90% times it indeed gets loaded. What's even more bizarre, when I've turned SQLDebug on I can see:

2013-04-12 12:00:27.934 SportLink[10831:c07] CoreData: annotation: fetch using
NSSQLiteStatement <0x12656d10> on entity 'Team' with sql text 'SELECT 0, t0.Z_PK,
t0.Z_OPT, t0.ZACI1, t0.ZACI2, t0.ZACI3, t0.ZALTFIRSTNAME, t0.ZALTSECONDNAME, t0.ZCOLOR1,
t0.ZCOLOR2, t0.ZGENDER, t0.ZICON, t0.ZID, t0.ZLOCATION, t0.ZLOGO1, t0.ZLOGO2, t0.ZNAME,
t0.ZTYPE, t0.ZSPORT FROM ZTEAM t0 WHERE  t0.ZID = ?  LIMIT 133' returned 6 rows

which means that the backing store actually fetched the data, but for some reason didn't pass it along. Now:

  • I'm doing everything in the main thread, so this is not an issue
  • I believe that autosaving is also not an issue, because this can happen even when I close the app and open it again with data already present.

Any ideas on what on earth is going on here?

Edit: I've profiled the app with Instruments. I just entered the problematic VC, then entered its child controller and leaved, repeated this a couple times until problem started to manifest itself. Here are the results. Maybe it will be easier to know what's going on from here:

Instruments output

like image 806
mav Avatar asked Apr 12 '13 10:04

mav


1 Answers

After few days of investigation, I finally found the cause of this bug. The code that was fetching Team entity looked like this:

Team *team = [Team findFirstByAttribute:WSK_ID withValue:data[WSK_ID] inContext:moc];

WSK_ID is just a define for @"id". data is a dictionary that I got from RestKit, from a JSON response. Because it wasn't cast to any type, it was probably a NSString, while the id property of Team entity was expecting NSNumber. While I don't know what it only failed sometimes, changing this bit to:

Team *team = [Team findFirstByAttribute:WSK_ID withValue:@([data[WSK_ID] intValue]) inContext:moc];

I.e. casting the ID string to int, and then boxing it with NSNumber fixed the problem.

like image 165
mav Avatar answered Sep 30 '22 10:09

mav