1

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
Community
  • 1
  • 1
se_puede_dev
  • 585
  • 7
  • 16

0 Answers0