diff --git a/SSDataKit/SSFilterableFetchedResultsController.h b/SSDataKit/SSFilterableFetchedResultsController.h index 9408755..6c05f94 100644 --- a/SSDataKit/SSFilterableFetchedResultsController.h +++ b/SSDataKit/SSFilterableFetchedResultsController.h @@ -21,6 +21,7 @@ @property (nonatomic, readonly) NSString *cacheName; @property (nonatomic, assign) id delegate; @property (nonatomic, readonly) NSArray *fetchedObjects; +@property (nonatomic, readonly) NSArray *unfilteredFetchedObjects; @property (nonatomic, readonly) NSArray *sections; // NSFetchedResultsController diff --git a/SSDataKit/SSFilterableFetchedResultsController.m b/SSDataKit/SSFilterableFetchedResultsController.m index de7d2ef..d4c209d 100644 --- a/SSDataKit/SSFilterableFetchedResultsController.m +++ b/SSDataKit/SSFilterableFetchedResultsController.m @@ -88,6 +88,30 @@ - (void)removeCurrentFilter { } +- (void)rebuildCurrentFilter +{ + [self.currentFilter.sections removeAllObjects]; + + for(int i = 0; i < self.fetchedResultsController.sections.count; i++) { + id section = (id)[self.fetchedResultsController.sections objectAtIndex:i]; + + SSFilteredResultsSection *newFilteredSection = [[SSFilteredResultsSection alloc] init]; + newFilteredSection.internalName = section.name; + newFilteredSection.internalIndexTitle = section.indexTitle; + + for(int j = 0; j < section.objects.count; j++) { + NSObject *o = [section.objects objectAtIndex:j]; + + if (self.currentFilter.predicate(o)) { + [newFilteredSection addObject:o]; + } + } + + [self.currentFilter.sections addObject:newFilteredSection]; + } +} + + - (void)_updateObjectsForCurrentFilter:(SSFilteredResultsFilter *)currentFilter newFilter:(SSFilteredResultsFilter *)newFilter { if ([(NSObject *)self.delegate respondsToSelector:@selector(controllerWillChangeContent:)]) { [self.delegate controllerWillChangeContent:self.fetchedResultsController]; @@ -149,15 +173,18 @@ - (void)_updateObjectsForCurrentFilter:(SSFilteredResultsFilter *)currentFilter for(int i = 0; i < currentFilter.sections.count; i++) { SSFilteredResultsSection *section = (SSFilteredResultsSection *)[currentFilter.sections objectAtIndex:i]; + // Delete rows that do not pass the new filter for(int j = 0; j < section.objects.count; j++) { NSObject *o = [section.objects objectAtIndex:j]; - if ([(NSObject *)self.delegate respondsToSelector:@selector(controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:)]) { - [self.delegate controller:self.fetchedResultsController - didChangeObject:o - atIndexPath:[NSIndexPath indexPathForRow:j inSection:i] - forChangeType:NSFetchedResultsChangeDelete - newIndexPath:nil]; + if (!newFilter.predicate(o)) { + if ([(NSObject *)self.delegate respondsToSelector:@selector(controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:)]) { + [self.delegate controller:self.fetchedResultsController + didChangeObject:o + atIndexPath:[NSIndexPath indexPathForRow:j inSection:i] + forChangeType:NSFetchedResultsChangeDelete + newIndexPath:nil]; + } } } } @@ -167,27 +194,52 @@ - (void)_updateObjectsForCurrentFilter:(SSFilteredResultsFilter *)currentFilter for(int i = 0; i < self.fetchedResultsController.sections.count; i++) { id section = (id)[self.fetchedResultsController.sections objectAtIndex:i]; + SSFilteredResultsSection *currentFilteredSection = [currentFilter.sections objectAtIndex:i]; SSFilteredResultsSection *filteredSection = [[SSFilteredResultsSection alloc] init]; filteredSection.internalName = section.name; filteredSection.internalIndexTitle = section.indexTitle; + // add all passable objects in section to the new filter for(int j = 0; j < section.objects.count; j++) { NSObject *o = [section.objects objectAtIndex:j]; if (newFilter.predicate(o)) { [filteredSection addObject:o]; + } + } + + [newFilter.sections addObject:filteredSection]; + for (int j = 0; j < filteredSection.objects.count; j++) { + NSObject *o = [filteredSection.objects objectAtIndex:j]; + BOOL foundInCurrentFilter = NO; + + for (int k = 0; k < currentFilteredSection.objects.count; k++) { + if (o == [currentFilteredSection.objects objectAtIndex:k]) { + foundInCurrentFilter = YES; + if (j != k) { + // Move rows that still pass the filter but need to be moved. + if ([(NSObject *)self.delegate respondsToSelector:@selector(controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:)]) { + [self.delegate controller:self.fetchedResultsController + didChangeObject:o + atIndexPath:[NSIndexPath indexPathForRow:k inSection:i] + forChangeType:NSFetchedResultsChangeMove + newIndexPath:[NSIndexPath indexPathForRow:j inSection:i]]; + } + } + } + } + if (!foundInCurrentFilter) { + // Insert rows that did not pass the current filter but do pass the new filter if ([(NSObject *)self.delegate respondsToSelector:@selector(controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:)]) { [self.delegate controller:self.fetchedResultsController didChangeObject:o atIndexPath:nil forChangeType:NSFetchedResultsChangeInsert - newIndexPath:[NSIndexPath indexPathForRow:([filteredSection numberOfObjects] - 1) inSection:i]]; + newIndexPath:[NSIndexPath indexPathForRow:j inSection:i]]; } } } - - [newFilter.sections addObject:filteredSection]; } } @@ -225,6 +277,11 @@ - (NSArray *)fetchedObjects { } +- (NSArray *)unfilteredFetchedObjects { + return self.fetchedResultsController.fetchedObjects; +} + + - (NSArray *)sections { if (self.currentFilter == nil) { return [self.fetchedResultsController sections]; @@ -310,11 +367,37 @@ - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { if ([(NSObject *)self.delegate respondsToSelector:@selector(controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:)]) { - // TODO: Currently change notifications for deletes are not supported while filtering - if (type != NSFetchedResultsChangeDelete) { - indexPath = [self indexPathForObject:anObject]; + if (self.currentFilter) { + if (type == NSFetchedResultsChangeInsert || type == NSFetchedResultsChangeUpdate) { + [self rebuildCurrentFilter]; + indexPath = [self indexPathForObject:anObject]; + if (indexPath) { + [self.delegate controller:controller didChangeObject:anObject atIndexPath:indexPath forChangeType:type newIndexPath:newIndexPath]; + } + } else if (type == NSFetchedResultsChangeMove) { + NSIndexPath *previousIndexInFilter = [self.currentFilter indexPathForObject:anObject]; + [self rebuildCurrentFilter]; + NSIndexPath *indexInFilter = [self.currentFilter indexPathForObject:anObject]; + + if (previousIndexInFilter && indexInFilter) { + [self.delegate controller:controller didChangeObject:anObject atIndexPath:indexPath forChangeType:NSFetchedResultsChangeMove newIndexPath:newIndexPath]; + } else if (!previousIndexInFilter && indexInFilter) { + newIndexPath = [self.currentFilter indexPathForObject:anObject]; + [self.delegate controller:controller didChangeObject:anObject atIndexPath:indexPath forChangeType:NSFetchedResultsChangeInsert newIndexPath:newIndexPath]; + } else if (previousIndexInFilter && !indexInFilter) { + indexPath = previousIndexInFilter; + [self.delegate controller:controller didChangeObject:anObject atIndexPath:indexPath forChangeType:NSFetchedResultsChangeDelete newIndexPath:newIndexPath]; + } + } else if (type == NSFetchedResultsChangeDelete) { + indexPath = [self.currentFilter indexPathForObject:anObject]; + if (indexPath) { + [self.delegate controller:controller didChangeObject:anObject atIndexPath:indexPath forChangeType:NSFetchedResultsChangeDelete newIndexPath:newIndexPath]; + } + [self rebuildCurrentFilter]; + } + } else { + [self.delegate controller:controller didChangeObject:anObject atIndexPath:indexPath forChangeType:type newIndexPath:newIndexPath]; } - [self.delegate controller:controller didChangeObject:anObject atIndexPath:indexPath forChangeType:type newIndexPath:newIndexPath]; } }