From d73920b5fa148669538ba1f4de67c5f26f4d16b0 Mon Sep 17 00:00:00 2001 From: Luke Stringer Date: Fri, 18 Apr 2014 22:52:58 +0100 Subject: [PATCH 1/5] SJOSearchableFetchedResultsController can be constructed with a managed object context. This allows a SJOSearchableFetchedResultsController to be constructed without the dependency on SJOStore. This is helpful if you only want to use this class without the the rest of SJODataKit, say with your own Core Data framework, or simply using standard Core Data classes. If the `store` property is set then the `managedObjectContext` property is set to be the `store.mainContext` managed object context. I think that another constructed should also be offered now, and the `store` property made readonly publicly. This way the `managedObjectContext` property would be immutable which would better as you would't want this changing after the object's construction. --- Library/SJOSearchableFetchedResultsController.h | 17 ++++++++++++++++- Library/SJOSearchableFetchedResultsController.m | 17 ++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Library/SJOSearchableFetchedResultsController.h b/Library/SJOSearchableFetchedResultsController.h index 98e1209..e71c23b 100644 --- a/Library/SJOSearchableFetchedResultsController.h +++ b/Library/SJOSearchableFetchedResultsController.h @@ -15,12 +15,27 @@ This class provides a simpler way to replicate the often-used pattern of a searc */ @interface SJOSearchableFetchedResultsController : UITableViewController +/** + * 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 a constructed with an 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; + /** The UISearchDisplayController used to manage the search interface. @discussion You can customise it in your subclass to enable scope buttons, etc. diff --git a/Library/SJOSearchableFetchedResultsController.m b/Library/SJOSearchableFetchedResultsController.m index b51d152..bedad0d 100644 --- a/Library/SJOSearchableFetchedResultsController.m +++ b/Library/SJOSearchableFetchedResultsController.m @@ -14,10 +14,20 @@ @interface SJOSearchableFetchedResultsController () @property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController; @property (strong, nonatomic) NSFetchedResultsController *searchFetchedResultsController; +@property (nonatomic, strong, readwrite) NSManagedObjectContext *managedObjectContext; @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 { @@ -200,10 +210,15 @@ - (SJODataStore *)store } } +- (void)setStore:(SJODataStore *)store { + _store = store; + self.managedObjectContext = store.mainContext; +} + - (NSFetchedResultsController *)newFetchedResultsControllerWithSearch:(NSString *)searchString { NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:[self fetchRequestForSearch:searchString] - managedObjectContext:self.store.mainContext + managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; fetchedResultsController.delegate = self; From b13cdc1153360ae6d32a5e5572d35b7635f74d31 Mon Sep 17 00:00:00 2001 From: Luke Stringer Date: Fri, 18 Apr 2014 22:58:49 +0100 Subject: [PATCH 2/5] Added `searchIsActive` property. This is helpful if you have a search-specific view setup. Say for example a tab bar controller is used. If a view controller is popped from the navigation stack to SJOSearchableFetchedResultsController which is actively searching, then the tab bar controller may want hiding. The `searchIsActive` property enables this behaviour. --- Library/SJOSearchableFetchedResultsController.h | 5 +++++ Library/SJOSearchableFetchedResultsController.m | 3 +++ 2 files changed, 8 insertions(+) diff --git a/Library/SJOSearchableFetchedResultsController.h b/Library/SJOSearchableFetchedResultsController.h index e71c23b..75ba344 100644 --- a/Library/SJOSearchableFetchedResultsController.h +++ b/Library/SJOSearchableFetchedResultsController.h @@ -36,6 +36,11 @@ This class provides a simpler way to replicate the often-used pattern of a searc */ @property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext; +/** + * Returns YES if the user is actively searching, i.e. the search bar has begun editting. 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. diff --git a/Library/SJOSearchableFetchedResultsController.m b/Library/SJOSearchableFetchedResultsController.m index bedad0d..2d6be8a 100644 --- a/Library/SJOSearchableFetchedResultsController.m +++ b/Library/SJOSearchableFetchedResultsController.m @@ -15,6 +15,7 @@ @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 @@ -258,6 +259,7 @@ - (NSFetchedResultsController *)searchFetchedResultsController - (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar { + self.searchIsActive = YES; [searchBar sizeToFit]; [searchBar setShowsCancelButton:YES animated:YES]; return YES; @@ -272,6 +274,7 @@ - (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar -(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { + self.searchIsActive = NO; [self searchBarShouldEndEditing:searchBar]; } From bad79014f9f246ddbd4d2431109f6e0bd5364538 Mon Sep 17 00:00:00 2001 From: Luke Stringer Date: Fri, 18 Apr 2014 23:09:09 +0100 Subject: [PATCH 3/5] Method can be overridden to specify a sectionKeyPath if a section index is to be displayed for the tableView. If `searchIsActive` is YES then the sectionKeyPath 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. --- Library/SJOSearchableFetchedResultsController.h | 15 ++++++++++++++- Library/SJOSearchableFetchedResultsController.m | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Library/SJOSearchableFetchedResultsController.h b/Library/SJOSearchableFetchedResultsController.h index 75ba344..f0a283d 100644 --- a/Library/SJOSearchableFetchedResultsController.h +++ b/Library/SJOSearchableFetchedResultsController.h @@ -37,7 +37,7 @@ This class provides a simpler way to replicate the often-used pattern of a searc @property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext; /** - * Returns YES if the user is actively searching, i.e. the search bar has begun editting. Returns NO after the user has cancelled the search. + * 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; @@ -97,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 diff --git a/Library/SJOSearchableFetchedResultsController.m b/Library/SJOSearchableFetchedResultsController.m index 2d6be8a..42d8218 100644 --- a/Library/SJOSearchableFetchedResultsController.m +++ b/Library/SJOSearchableFetchedResultsController.m @@ -216,11 +216,24 @@ - (void)setStore:(SJODataStore *)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.managedObjectContext - sectionNameKeyPath:nil + sectionNameKeyPath:sectionKeyPath cacheName:nil]; fetchedResultsController.delegate = self; NSError *error = nil; From 1eaa518ab921d63e97f851c081f1e8655d24370c Mon Sep 17 00:00:00 2001 From: Luke Stringer Date: Fri, 18 Apr 2014 23:22:53 +0100 Subject: [PATCH 4/5] Typo fix. --- Library/SJOSearchableFetchedResultsController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/SJOSearchableFetchedResultsController.h b/Library/SJOSearchableFetchedResultsController.h index f0a283d..d3765d4 100644 --- a/Library/SJOSearchableFetchedResultsController.h +++ b/Library/SJOSearchableFetchedResultsController.h @@ -27,7 +27,7 @@ This class provides a simpler way to replicate the often-used pattern of a searc /** The SJODataStore to be used when querying data. - @warning This must be set before the view is loaded unless a constructed with an managed object context. + @warning This must be set before the view is loaded unless constructed with an managed object context. */ @property (strong, nonatomic) SJODataStore *store; From d3a6cb9b83f651d255a0250945bb842dba458d28 Mon Sep 17 00:00:00 2001 From: Luke Stringer Date: Fri, 18 Apr 2014 23:23:24 +0100 Subject: [PATCH 5/5] Typo fix. --- Library/SJOSearchableFetchedResultsController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/SJOSearchableFetchedResultsController.h b/Library/SJOSearchableFetchedResultsController.h index d3765d4..13d314f 100644 --- a/Library/SJOSearchableFetchedResultsController.h +++ b/Library/SJOSearchableFetchedResultsController.h @@ -27,7 +27,7 @@ This class provides a simpler way to replicate the often-used pattern of a searc /** The SJODataStore to be used when querying data. - @warning This must be set before the view is loaded unless constructed with an managed object context. + @warning This must be set before the view is loaded unless constructed with a managed object context. */ @property (strong, nonatomic) SJODataStore *store;