1

I have an iOS app that is built on a tabBarViewController. The App utilizes Restkit to pull data from a Restful web service which is persisted in CoreData. In the event a user wants to logout of the app, I have a logout button that triggers a method to delete all objects in the CoreData entities. The main/home tab in the app is a UICollectionView. The second tab has a UITableView, and the last tab has a static table with two cells. One of the cells in the last tab allows the user to log out of the app.

By chance I noticed that when I logout, the numberOfSections and numberOfRows methods of the previous viewController I had open are getting triggered when I delete the entity that pertains to them. For example my collectionView is populated with data persisted in the Gist entity. If the user was viewing the collectionView and navigated to the settings tab and chose to logout, my deleteAllEntitiesForName method will then be called. When the method is told to delete the objects in the Gist entity, for some reason the numberOfSections and numberOfRows methods are called in the viewController for the collectionView! The same will happen in the UITableViewController if that is where the user navigated from.

Why are methods from a totally separate view controller being hit when I am just clearing out data?

I am using NSLog to be notified that these functions are getting triggered.

Even stranger, if I login and logout consecutively the methods will be called once for each time I have logged out. Here is the proof from my console....

First Logout after a build and run in the simulator:

2014-01-16  delete Gist
2014-01-16  Check numberOfSectionsInCollectionView
2014-01-16  Check numberofItemsInSection
2014-01-16  delete ActivityData
2014-01-16  delete FollowActivityData
2014-01-16  delete InsertNodes

Login and log back out while still running the app in the simulator:

2014-01-16  delete Gist
2014-01-16  Check numberOfSectionsInCollectionView
2014-01-16  Check numberofItemsInSection
2014-01-16  Check numberOfSectionsInCollectionView
2014-01-16  Check numberofItemsInSection
2014-01-16  delete ActivityData
2014-01-16  delete FollowActivityData
2014-01-16  delete InsertNodes

Here is the method I am using to clear the data persisted in the entities.

- (void) deleteAllEntitiesForName:(NSString*)entityName {
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName: entityName inManagedObjectContext:managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDescription];
    NSError *error = nil;
    NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
    if (array != nil) {
        for(NSManagedObject *managedObject in array) {
            [managedObjectContext deleteObject:managedObject];
        }
        error = nil;
        [managedObjectContext save:&error];
    }

}

I can't say that I notice any problems with the way the app runs. I've confirmed that all the data is cleared from the core data entities. But I am concerned that I may be doing something wrong here. The especially concerning part is that the methods are triggered once for every time the user has logged out.

Does anyone have any idea what is going on here? Should I be concerned? How do I handle this? Thanks for the input!

I believe I got the deleteAllEntitiesForName method from here Delete/Reset all entries in Core Data?

===========UPDATE============

The collectionView and tableView are populated using a FetchedResultsController. Here is my implementation along with commentary of some of some of my findings.

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
   atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
  newIndexPath:(NSIndexPath *)newIndexPath
{
    NSLog(@"CHECK didChangeObject");
    //THIS METHOD IS TRIGGERED FIRST AFTER THE DELETE HAS STARTED.
    //IT IS TRIGGERED ONCE FOR EVERY CELL IN THE COLLECTION OR ONCE FOR EVERY ROW IN THE TABLE
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    NSLog(@"CHECK didChangeContent");
    //THIS METHOD IS TRIGGERED NEXT.  IT IS TRIGGERED ONCE AFTER ALL THE OBJECT DATA WAS DELETED IN THE METHOD ABOVE.
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
    NSLog(@"Check numberOfSectionsInCollectionView");
    return [[self.fetchedResultsController sections] count];
    //THIS METHOD IS THEN TRIGGERED FOLLOWED BY THE FETCHED RESULTS CONTROLLER
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    NSLog(@"Check numberofItemsInSection");
    id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
    return [sectionInfo numberOfObjects];
    //FOLLOWING THE FRC THIS METHOD IS CALLED AND ONCE AGAIN THE FRC IS TRIGGERED
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    //THIS IS WHERE GUTS OF THE CELLS ARE POPULATED.  I LEFT IT OUT FOR BREVITY.
    //THIS METHOD IS NEVER TRIGGERED WHEN CLEARING OUT THE CORE DATA.
}
Community
  • 1
  • 1
Ben
  • 967
  • 3
  • 9
  • 23
  • Just one of the many weird side effects one gets from using Core Data. It seems to stay stuck to everything. We have moved or are moving all our stuff to FMDB from Core Data. – HalR Jan 17 '14 at 04:34
  • I personally doubt this has anything to do with core data, and more likely how you implemented those views. Any chance you could like to the project on github or similar to look through and debug? – Mike Jan 17 '14 at 05:02
  • It's not 'one of the many weird side effects' from using Core Data. Something in your implementation is telling the collectionView / tableView that something has changed. Core Data will not magically do that for you. – Mike Pollard Jan 17 '14 at 11:26

1 Answers1

0

You might (guessing, since you don't say) be using a FetchedResultsController as the data source for your tables.

If so, be aware that FRC objects are "active" in the sense that they proactively respond to changes in their data (the Core Data contents they are linked to). If you change data out from under them, they notice and respond. And if you have them linked as data sources for UITableViews, they're going to tell the table views about it.

If you'd care to post some details about how your data is linked from core data to your table views, we could better help you understand why Core Data changes are generating messages to the TableView.

Bill Patterson
  • 2,495
  • 1
  • 19
  • 20
  • Indeed I am using a FRC as the data source for the collectionView and tableView. I'll update my question to reflect this. – Ben Jan 19 '14 at 00:32
  • Bill I definitely agree with what you are saying about the active nature of the FRC. After reading your statement I added a few more logs to monitor the activity of the FRC. I found that the FRC and its supporting methods (specifically didChangeObject...atIndexPath...) is triggered every time I delete the supporting object data. Now for the question. Is this a problem? Seems like it is behaving the way it is supposed to. – Ben Jan 19 '14 at 01:09
  • I think, based on limit understanding, that this is not a problem for your case. With UINavigationControllers and UITabBarControllers, you can have VC's that are still "alive" but off screen. The notifications are getting sent to these objects, and they're updating their state accordingly. But they're off-screen, so no real harm done (just updating objects in memory). The only harm would be if you have stuff that's watching for state changes on the UITableView, which would be really, really unusual and something you would have written yourself. – Bill Patterson Jan 19 '14 at 02:17
  • Fair enough, I'll accept that. I do still have the issue with the methods getting triggered once for every time the user has logged out. There is obviously a memory management issue I have overlooked here. In the event that you or anyone else realizes why that would occur please edit your solution to reflect that! Thanks Bill! – Ben Jan 19 '14 at 02:38
  • You can have all the issues you want. :-) But it's the nature of a FetchedResultsController that it's *supposed* to tell a table view every time the objects it contains get modified. Dynamic monitoring and updating of Core Data objects is it's entire purpose. If you want it to not be taking action when you delete objects from the Core Data store, then you need to disconnect/erase the FRC's before you start making modifications to the stored Core Data objects. – Bill Patterson Jan 19 '14 at 02:42
  • Or, alternatively, don't use FetchedResultControllers to drive your tables. There's no reason you have to. You can, on ViewWillAppear, re-query Core Data manually to get a list of objects, and store that as the DataSource for the table. But in that case you have to now be careful about refreshing that list every time you display the table, since objects may have been deleted and you'll now be unable to use them to if the UITableView asks for data. – Bill Patterson Jan 19 '14 at 02:46