搜索 NSDictionary 的 NSArray(其中包含 NSDictionary 的 NSArray,重复)
我有一个数据结构(在 plist 中),看起来像这样:
我这里有一个NSDictionary
的 NSArray
。每个 NSDictionary 有两个键:
Title
Link (recursive)
这形成了一个树状结构,具有可变长度的分支,即一些分支可以在第 0 级消亡,而有些分支可以达到第 3 级或更高级别。
我在 UITableView
中展示了这个结构(在 UINavigationController
的帮助下)。这很容易。
注意:点击叶节点时 (由
NSDictionary
对象表示 以Nil或零作为“链接”), 事件被触发,即模型窗口 出现一些信息。
现在,我需要添加搜索支持。
搜索栏将出现在 UITabeView
上方(针对 0 级)。我需要想出一种方法来搜索这种树状结构,然后使用 UISearchDisplayController 显示结果,然后也允许用户导航结果。
如何?...是我有点卡住的地方 并需要一些建议。
搜索必须快速,因为我们希望在您键入时进行搜索。
ps我曾想过将这个数据结构翻译成CoreData,但它仍然潜伏在我的脑海中。如果您认为这对这种情况有帮助,请提出建议。
编辑: 这是我当前的解决方案,它正在工作(顺便说一下):
#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 array];
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;
}
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 byNSDictionary
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 array];
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
核心数据将能够非常有效地在数据存储中执行搜索,并且可以有效地将搜索扩展到更多级别。另外,如果您使用 NSFetchedResultsController对于 TableView 来说,它几乎肯定会提高内存效率 - 最坏的情况是在任何给定时间只加载一级数组。最好的情况要好得多,因为它只有 将一些对象放入数组中。华泰
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