Search NSArray of NSDictionary (which contains NSArray of NSDictionary, repeatedly)
I have a data-structure (in plist) that looks something like this:
What i have here is an NSArray
of NSDictionary
. Each NSDictionary
has two keys:
Title
Link (recursive)
This forms a tree like structure, with variable length branches i.e. some branches can die at level 0, and some can be as large as level 3 or more.
I'm showing this structure in UITableView
(with a little help from UINavigationController
). This was easy enough.
Note: On tapping the Leaf Node (represented by
NSDictionary
object with Nil or Zero as "Link"), an event is triggered i.e. Model window appears with some information.
Now, i need to add Search support.
Search bar will appear above UITabeView
(for Level 0). I need to come-up with a way to search this tree like structure, and then show the results using UISearchDisplayController
, and then allow users to navigate the results as well.
How?... is where i'm a little stuck and need some advise.
The search has to be quick, because we want search as you type.
p.s. I've thought of translating this data structure to CoreData, and it's still lurking in my mind. If you think it can help in this case, please advise.
Edit: Here's my current solution, which is working (by the way):
#pragma mark -
#pragma mark UISearchDisplayController methods
- (void)searchBarResultsListButtonClicked:(UISearchBar *)searchBar {
NSLog(@"%s", __FUNCTION__);
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
NSLog(@"%s", __FUNCTION__);
[self filterCategoriesForSearchText:searchString
scope:[controller.searchBar selectedScopeButtonIndex]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
NSLog(@"%s", __FUNCTION__);
[self filterCategoriesForSearchText:[controller.searchBar text]
scope:[controller.searchBar selectedScopeButtonIndex]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
#pragma mark UISearchDisplayController helper methods
- (void)filterCategoriesForSearchText:(NSString *)searchText scope:(NSInteger)scope {
self.filteredCategories = [self filterCategoriesInArray:_categories forSearchText:searchText];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:KEY_DICTIONARY_TITLE ascending:YES] autorelease];
[self.filteredCategories sortUsingDescriptors:[NSArray arrayWithObjects:descriptor, nil]];
}
- (NSMutableArray *)filterCategoriesInArray:(NSArray *)array forSearchText:(NSString *)searchText {
NSMutableArray *resultArray = [NSMutableArray a开发者_高级运维rray];
NSArray *filteredResults = nil;
// Apply filter to array
// For some weird reason this is not working. Any guesses? [NSPredicate predicateWithFormat:@"%@ CONTAINS[cd] %@", KEY_DICTIONARY_TITLE, searchText];
NSPredicate *filter = [NSPredicate predicateWithFormat:@"Title CONTAINS[cd] %@", searchText];
filteredResults = [array filteredArrayUsingPredicate:filter];
// Store the filtered results (1)
if ((filteredResults != nil) && ([filteredResults count] > 0)) {
[resultArray addObjectsFromArray:filteredResults];
}
// Loop on related records to find the matching results
for (NSDictionary *dictionayObject in array) {
NSArray *innerCategories = [dictionayObject objectForKey:KEY_DICTIONARY_LINK];
if ((innerCategories != nil) && ([innerCategories count] > 0)) {
filteredResults = [self filterCategoriesInArray:innerCategories forSearchText:searchText];
// Store the filtered results (2)
if ((filteredResults != nil) && ([filteredResults count] > 0)) {
[resultArray addObjectsFromArray:filteredResults];
}
}
}
return resultArray;
}
Core Data would be able to perform the search in the data store pretty efficiently, and would scale the search to more levels efficiently. Also, if you use NSFetchedResultsController for the TableView it would almost certainly be more memory efficient - the worst case would only have one level array loaded at any given time. And the best case is considerably better, as it would only have faulted a few objects into the array. HTH
精彩评论