Skip to content
This repository has been archived by the owner on Aug 24, 2019. It is now read-only.

Refactor SSFilterableFetchedResultsController filter updates. #21

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions SSDataKit/SSFilterableFetchedResultsController.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
@property (nonatomic, readonly) NSString *cacheName;
@property (nonatomic, assign) id<NSFetchedResultsControllerDelegate> delegate;
@property (nonatomic, readonly) NSArray *fetchedObjects;
@property (nonatomic, readonly) NSArray *unfilteredFetchedObjects;
@property (nonatomic, readonly) NSArray *sections;

// NSFetchedResultsController
Expand Down
109 changes: 96 additions & 13 deletions SSDataKit/SSFilterableFetchedResultsController.m
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,30 @@ - (void)removeCurrentFilter {
}


- (void)rebuildCurrentFilter
{
[self.currentFilter.sections removeAllObjects];

for(int i = 0; i < self.fetchedResultsController.sections.count; i++) {
id<NSFetchedResultsSectionInfo> section = (id<NSFetchedResultsSectionInfo>)[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];
Expand Down Expand Up @@ -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];
}
}
}
}
Expand All @@ -167,27 +194,52 @@ - (void)_updateObjectsForCurrentFilter:(SSFilteredResultsFilter *)currentFilter
for(int i = 0; i < self.fetchedResultsController.sections.count; i++) {
id<NSFetchedResultsSectionInfo> section = (id<NSFetchedResultsSectionInfo>)[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];
}
}

Expand Down Expand Up @@ -225,6 +277,11 @@ - (NSArray *)fetchedObjects {
}


- (NSArray *)unfilteredFetchedObjects {
return self.fetchedResultsController.fetchedObjects;
}


- (NSArray *)sections {
if (self.currentFilter == nil) {
return [self.fetchedResultsController sections];
Expand Down Expand Up @@ -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];
}
}

Expand Down