Search code examples
afnetworkingfmdb

What's the correct way to use inDatabase: within an async networking call?


I'm using AFNetworking along with FMDB to remove database rows from an array when I make a successful POST to a server. My problem at the moment is that my logging shows that I'm skipping every second item in the array, so I think I've incorrectly used FMDB in conjunction with AFNetworking's async request.

This is what the code looks like:

[manager POST:[_urlEndpoint absoluteString] parameters:data success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
    [_dbQueue inDatabase:^(FMDatabase *db) {
        for (int i = 0; i < arrayOfIds.count; ++i)
        {
            NSLog(@"Removing event at index: %@", arrayOfIds[i]);
            [_db removeWithId:arrayOfIds[i]];
        }
    }];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

In the arrayOfIds, the logs shows that I hit 1, skip 2, hit 3, skip 4, etc. In this particular case, I've made sure I'm only sending one POST request so narrow down the root cause so I know there aren't multiple accesses to arrayOfIds.

What could I have done wrong that I may have missed?

(Possibly) related question I just asked before: FMDB: Does calling a method to make a query in the inDatabase block work the same way?

EDIT: Here are what my logs look like..

2014-07-13 03:08:28.684 PostTestApp[77268:6675567] Adding event to array to be sent: 1
2014-07-13 03:08:28.684 PostTestApp[77268:6675567] Adding event to array to be sent: 2
2014-07-13 03:08:28.684 PostTestApp[77268:6675567] Adding event to array to be sent: 3
2014-07-13 03:08:28.684 PostTestApp[77268:6675567] Adding event to array to be sent: 4
2014-07-13 03:08:28.684 PostTestApp[77268:6675567] Adding event to array to be sent: 5
2014-07-13 03:08:28.684 PostTestApp[77268:6675567] Adding event to array to be sent: 6
2014-07-13 03:08:29.191 PostTestApp[77268:6675567] JSON: {
    description = "Server response from /events";
    name = response;
}
2014-07-13 03:08:29.192 PostTestApp[77268:6675567] Removing event at index: 1
2014-07-13 03:08:29.192 PostTestApp[77268:6675567] Removed event from row: 1
2014-07-13 03:08:29.195 PostTestApp[77268:6675567] Removing event at index: 3
2014-07-13 03:08:29.195 PostTestApp[77268:6675567] Removed event from row: 3
2014-07-13 03:08:29.196 PostTestApp[77268:6675567] Removing event at index: 5
2014-07-13 03:08:29.197 PostTestApp[77268:6675567] Removed event from row: 5
  • "Adding event to array to be sent:" is a for-loop that adds database IDs into arrayOfIds.
  • "Removing event at index:" happens inside the inDatabase: block.
  • "Removed event from row:" happens inside removeWithId:.

EDIT 2:

Full code block without edits: https://gist.github.com/jonalmeida/27bee72b9015d45434e8


Solution

  • According to your gist, your actual code looks like this:

    for (int i=0; i < dbIndexArray.count; i++) {
        NSLog(@"Removing event at index: %@", dbIndexArray[i]);
        [_db removeEventWithId:[[dbIndexArray objectAtIndex:i] longLongValue]];
        [dbIndexArray removeObjectAtIndex:i];
    }
    

    The problem is: you are modifying the array while you're iterating through it. When you remove object 0, and object 1 becomes object 0.

    Try this:

    NSMutableArray *removedIDs = [NSMutableArray array];
    
    for (int i=0; i < dbIndexArray.count; i++) {
        NSLog(@"Removing event at index: %@", dbIndexArray[i]);
        [_db removeEventWithId:[[dbIndexArray objectAtIndex:i] longLongValue]];
        [removedIDs addObject:dbIndexArray[i];
    }
    
    [dbIndexArray removeObjectsInArray:removedIDs];