Skip to content
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
35 changes: 34 additions & 1 deletion Library/SJOSearchableFetchedResultsController.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,32 @@ This class provides a simpler way to replicate the often-used pattern of a searc
*/
@interface SJOSearchableFetchedResultsController : UITableViewController<UISearchBarDelegate, UISearchDisplayDelegate, NSFetchedResultsControllerDelegate>

/**
* Initialises a Core Data-backed UITableViewController with a configured with a UISearchDispalyController.
*
* @param context The managed object context to use when query Core Data.
* @param style A constant that specifies the style of table view that the controller object is to manage (UITableViewStylePlain or UITableViewStyleGrouped).
*
* @return An initialized SJOSearchableFetchedResultsController object or nil if the object couldn’t be created.
*/
- (instancetype)initWithContext:(NSManagedObjectContext *)managedObjectContext style:(UITableViewStyle)style;

/**
The SJODataStore to be used when querying data.
@warning This must be set before the view is loaded.
@warning This must be set before the view is loaded unless constructed with a managed object context.
*/
@property (strong, nonatomic) SJODataStore *store;

/**
* The managed object context used. If the store property is set this is the `mainContext` of the SJOStore instance.
*/
@property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext;

/**
* Returns YES if the user is actively searching, i.e. the search bar has begun editing. Returns NO after the user has cancelled the search.
*/
@property(nonatomic, assign, readonly) BOOL searchIsActive;

/**
The UISearchDisplayController used to manage the search interface.
@discussion You can customise it in your subclass to enable scope buttons, etc.
Expand Down Expand Up @@ -77,4 +97,17 @@ Forces the fetched results controllers to be recreated, causing performFetch to
*/
- (void) reloadFetchedResultsControllers;

/**---------------------------------------------------------------------------------------
* @name Methods that can overridden in subclass, but defaults are used otherwise.
* ---------------------------------------------------------------------------------------
*/
/**
* Returns the section key path string to use when constructing new NSFetchedResultsControllers. nil by default, so without overriding NSFetchedResultsControllers will have no sections. NOTE: if `searchIsActive` is YES then the return value will be ignored and nil used regardless. This is because A a section index should not be shown while searching, and B executed fetch requests take longer when sections are used. When searching this is especially noticable as a new fetch request is executed upon each key stroke during search.
*
* @param controller The SJOSearchableFetchedResultsController creating the NSFetchedResultsController for which a sectionKeyPath is needed.
*
* @return The sectionKeyPath to use in constructing a NSFetchedResultsController, or nil for no sections.
*/
- (NSString *)sectionKeyPathForSearchableFetchedResultsController:(SJOSearchableFetchedResultsController *)controller;

@end
35 changes: 33 additions & 2 deletions Library/SJOSearchableFetchedResultsController.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,21 @@
@interface SJOSearchableFetchedResultsController ()
@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
@property (strong, nonatomic) NSFetchedResultsController *searchFetchedResultsController;
@property (nonatomic, strong, readwrite) NSManagedObjectContext *managedObjectContext;
@property(nonatomic, assign, readwrite) BOOL searchIsActive;
@end

@implementation SJOSearchableFetchedResultsController

// To override the setter the property must be synthesized
@synthesize store = _store;

- (instancetype)initWithContext:(NSManagedObjectContext *)managedObjectContext style:(UITableViewStyle)style {
if ([super initWithStyle:style]) {
self.managedObjectContext = managedObjectContext;
}
return self;
}

- (void)viewDidLoad
{
Expand Down Expand Up @@ -200,11 +211,29 @@ - (SJODataStore *)store
}
}

- (void)setStore:(SJODataStore *)store {
_store = store;
self.managedObjectContext = store.mainContext;
}

- (NSString *)sectionKeyPathForSearchableFetchedResultsController:(SJOSearchableFetchedResultsController *)controller {
return nil;
}

- (NSFetchedResultsController *)newFetchedResultsControllerWithSearch:(NSString *)searchString
{
NSString *sectionKeyPath;
/**
* Only use a sectionKeyPath when not searching becuase:
* - A a section index should not be shown while searching, and
* - B executed fetch requests take longer when sections are used. When searching this is especially noticable as a new fetch request is executed upon each key stroke during search.
*/
if (!self.searchIsActive) {
sectionKeyPath = [self sectionKeyPathForSearchableFetchedResultsController:self];
}
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:[self fetchRequestForSearch:searchString]
managedObjectContext:self.store.mainContext
sectionNameKeyPath:nil
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:sectionKeyPath
cacheName:nil];
fetchedResultsController.delegate = self;
NSError *error = nil;
Expand Down Expand Up @@ -243,6 +272,7 @@ - (NSFetchedResultsController *)searchFetchedResultsController

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
self.searchIsActive = YES;
[searchBar sizeToFit];
[searchBar setShowsCancelButton:YES animated:YES];
return YES;
Expand All @@ -257,6 +287,7 @@ - (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar

-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
self.searchIsActive = NO;
[self searchBarShouldEndEditing:searchBar];
}

Expand Down