I've seen another question here that helped me a lot, but I'm still having issues with my particular configuration. I'm using what some people refer to as 'slim view controllers' which means that I have an object with a single protocol method to configure tableViewCells and the tableview's dataSource/delegate and NSFetchedResultsController delegate methods. The biggest reason I'm using this particular setup is I can create a single superclass with that has all my segues and a single dataSource property. It's been working well, except for one page that has a UISegmentedControl where I have to change this dataSource object for the view controller. I can set it and interact with the view controller as expected, but as it is now, I can set the selectedSegmentIndex to 1, and I can reset it to 0, but the tableView doesn't update correctly (it still will show as having a selectedSegmentIndex of 1). For a long time I was having trouble making the tableView work at all when the selectedSegmentIndex was 1 — I was getting messages saying that An Objective-C message was sent to a deallocated 'LSTFetchedResultsControllerDataSource' object (zombie) at address: 0x198a90f0.
Any ideas why I can reset the selectedSegmentIndex to 0, but the corresponding tableView doesn't show the proper data?
// ViewController - LSTFavoriteSpeeches.h
@interface LSTFavoriteSpeeches : LSTSpeechBaseTBVC <FetchedResultsControllerDataSourceDelegate>
@property (nonatomic, strong) LSTFetchedResultsControllerDataSource *currentDataSource;
@property (weak, nonatomic) IBOutlet UISegmentedControl *favoriteSegmentedControl;
- (IBAction)toggleFavoriteSpeechesandSpeakers:(id)sender;
@end
// ViewController - LSTFavoriteSpeeches.m
@interface LSTFavoriteSpeeches ()
@property (nonatomic, strong) LSTFetchedResultsControllerDataSource *favoriteSpeechesDataSource;
@property (nonatomic, strong) LSTFetchedResultsControllerDataSource *favoriteSpeakersDataSource;
@property (nonatomic, strong) NSFetchedResultsController *favoriteSpeechesFRC;
@property (nonatomic, strong) NSFetchedResultsController *favoriteSpeakersFRC;
@property (nonatomic, strong) NSFetchedResultsController *currentFRC;
@property (nonatomic, copy) NSString *currentCellNibName;
@property (nonatomic, copy) NSString *currentCellIdentifier;
@end
@implementation LSTFavoriteSpeeches
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSManagedObjectContext *managedObjectContext = [[LSTSharedMOC sharedMOC] sharedManagedObjectContext];
/* Set the favoriteSpeechesFRC, if tere are any favorite speeches to be fetched, otherwise, set it to nil */
self.favoriteSpeechesFRC = [managedObjectContext executeFetchRequest:[LSTFetchData favoriteSpeakersSortedByTitle:NO] error:nil]
? self.favoriteSpeechesFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:[LSTFetchData favoriteSpeechesSortedByTitle:NO] managedObjectContext:managedObjectContext sectionNameKeyPath:@"speechType" cacheName:nil]//;@"LSTFavoriteSpeeches"];
: nil;
self.favoriteSpeakersFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:[LSTFetchData favoriteSpeakersSortedByTitle:NO] managedObjectContext:managedObjectContext sectionNameKeyPath:@"lastNameInitial" cacheName:nil];
[self toggleFavoriteSpeechesandSpeakers:self.favoriteSegmentedControl];
}
- (void)configureCell:(id)cell withObject:(id)object {
super.dataSource = self.currentDataSource;
[super configureCell:cell withObject:object];
}
- (IBAction)toggleFavoriteSpeechesandSpeakers:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 0) {
self.favoriteSpeechesDataSource = [[LSTFetchedResultsControllerDataSource alloc] initWithTableView:self.tableView withFetchedResultsController:self.favoriteSpeechesFRC reuseIdentifier:LSTSpeechCellIdentifier andNibName:LSTSpeechTableCellNibName];
self.currentCellIdentifier = LSTSpeechCellIdentifier;
self.currentCellNibName = LSTSpeechTableCellNibName;
self.favoriteSpeechesDataSource.delegate = self;
self.currentDataSource = self.favoriteSpeechesDataSource;
} else {
self.favoriteSpeakersDataSource = [[LSTFetchedResultsControllerDataSource alloc] initWithTableView:self.tableView withFetchedResultsController:self.favoriteSpeakersFRC reuseIdentifier:LSTSpeakerCellIdentifier andNibName:LSTSpeakerTableCellNibName];
self.currentCellIdentifier = LSTSpeakerCellIdentifier;
self.currentCellNibName = LSTSpeakerTableCellNibName;
self.favoriteSpeakersDataSource.delegate = self;
self.currentDataSource = self.favoriteSpeakersDataSource;
}
[self.tableView registerNib:[UINib nibWithNibName:self.currentCellNibName bundle:nil] forCellReuseIdentifier:self.currentCellIdentifier];
[self.tableView reloadData];
}
@end
// DataSource - LSTFetchedResultsControllerDataSource.h
@interface LSTFetchedResultsControllerDataSource : NSObject <UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate>
@property (nonatomic, weak) id <FetchedResultsControllerDataSourceDelegate> delegate;
@property (readonly, strong) NSFetchedResultsController *fetchedResultsController;
@property (readonly, strong) UITableView *tableView;
@property (readonly, copy) NSString *reuseIdentifier;
@property (readonly, copy) NSString *nibName;
@property (readonly) NSEntityDescription *entity;
- (id)initWithTableView:(UITableView *)tableView
withFetchedResultsController:(NSFetchedResultsController *)fetchedResultsController
reuseIdentifier:(NSString *)reuseIdentifier
andNibName:(NSString *)nibName;
@end
// DataSource - LSTFetchedResultsControllerDataSource.m
@interface LSTFetchedResultsControllerDataSource ()
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, copy) NSString *reuseIdentifier;
@property (nonatomic, copy) NSString *nibName;
@end
@implementation LSTFetchedResultsControllerDataSource
#pragma mark - Initilializers
- (id)initWithTableView:(UITableView *)tableView withFetchedResultsController:(NSFetchedResultsController *)fetchedResultsController reuseIdentifier:(NSString *)reuseIdentifier andNibName:(NSString *)nibName {
if (self = [super init]) {
_tableView = tableView;
_tableView.dataSource = self;
_fetchedResultsController = fetchedResultsController;
_fetchedResultsController.delegate = self;
NSError *error;
if ((self.fetchedResultsController != nil) && (![self.fetchedResultsController performFetch:&error])) {
NSLog(@"Unresolved error %@ -- %@", error, error.userInfo);
abort();
}
_reuseIdentifier = reuseIdentifier;
_nibName = nibName;
}
return self;
}
#pragma mark - UITableViewDataSource Delegate Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionIndex {...}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {...}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {...}
#pragma mark - NSFetchedResultsController Delegate Methods
- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller {
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller {
[self.tableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
NSLog(@"NSFetchedResultsChangeInsert");
break;
case NSFetchedResultsChangeMove:
NSLog(@"section changed - type - NSFetchedResultsChangeMove");
break;
case NSFetchedResultsChangeUpdate:
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
NSLog(@"NSFetchedResultsChangeUpdate");
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
NSLog(@"NSFetchedResultsChangeDelete");
break;
}
}
- (void)controller:(NSFetchedResultsController*)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath*)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath*)newIndexPath {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
// [self.tableView reloadRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone];
break;
}
}
@end