为什么我的 UISearchDisplayController 不会触发 didSelectRowAtIndexPath 方法?

发布于 2024-09-02 02:02:37 字数 6437 浏览 13 评论 0原文

使用 UISearchDisplayController 搜索 UITableView 时遇到一个奇怪的问题。 UITableViewController 是另一个 UITableViewController 的子类,具有有效的 didSelectRowAtIndexPath 方法。如果不搜索控制器,则可以很好地处理选择,向超类发送 didSelectRowAtIndexPath 调用,但如果我在搜索时选择一个单元格,则超类不会收到任何内容,但单元格会突出显示。下面是我的子类的代码。

@implementation AdvancedViewController


@synthesize searchDisplayController, dict, filteredList;


- (void)viewDidLoad {
    [super viewDidLoad];

    // Programmatically set up search bar
    UISearchBar *mySearchBar = [[UISearchBar alloc] init];
    mySearchBar.delegate = self;
    [mySearchBar setAutocapitalizationType:UITextAutocapitalizationTypeNone];
    [mySearchBar sizeToFit];
    self.tableView.tableHeaderView = mySearchBar;

    // Programmatically set up search display controller
    searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:mySearchBar contentsController:self];
    [self setSearchDisplayController:searchDisplayController];
    [searchDisplayController setDelegate:self];
    [searchDisplayController setSearchResultsDataSource:self];

    // Parse data from server
    NSData * jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
    NSArray * items = [[NSArray alloc] initWithArray:[[CJSONDeserializer deserializer] deserializeAsArray:jsonData error:nil]];

    // Init variables
    dict = [[NSMutableDictionary alloc] init];
    listIndex = [[NSMutableArray alloc] init];
    fullList = [[NSMutableArray alloc] init];
    filteredList = [[NSMutableArray alloc] init];

    // Get each item and format it for the UI
    for(NSMutableArray * item in items) {
        // Get the first letter
        NSString * firstKey = [[[item objectAtIndex:0] substringWithRange:NSMakeRange(0,1)] uppercaseString];

        // Put symbols and numbers in the same section
        if ([[firstKey stringByTrimmingCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]] isEqualToString:@""]) firstKey = @"#";

        // If there isn't a section with this key
        if (![listIndex containsObject:firstKey]) {
            // Add the key to the index for faster access (because it's already sorted)
            [listIndex addObject:firstKey];
            // Add the key to the unordered dictionary
            [dict setObject:[NSMutableArray array] forKey:firstKey];
        }
        // Add the object to the dictionary
        [[dict objectForKey:firstKey] addObject:[[NSMutableDictionary alloc] initWithObjects:item forKeys:[NSArray arrayWithObjects:@"name", @"url", nil]]];
        // Add the object to the list for simple searching
        [fullList addObject:[[NSMutableDictionary alloc] initWithObjects:item forKeys:[NSArray arrayWithObjects:@"name", @"url", nil]]];
    }

    filteredList = [NSMutableArray arrayWithCapacity:[fullList count]];
}


#pragma mark -
#pragma mark Table view data source

// Custom method for object oriented data access
- (NSString *)tableView:(UITableView *)tableView dataForRowAtIndexPath:(NSIndexPath *)indexPath withKey:(NSString *)key {
    return (NSString *)((tableView == self.searchDisplayController.searchResultsTableView) ? 
                        [[filteredList objectAtIndex:indexPath.row] objectForKey:key] :
                        [[[dict objectForKey:[listIndex objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row] valueForKey:key]);
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return (tableView == self.searchDisplayController.searchResultsTableView) ? 1 : (([listIndex count] > 0) ? [[dict allKeys] count] : 1);
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return (tableView == self.searchDisplayController.searchResultsTableView) ? [filteredList count] : [[dict objectForKey:[listIndex objectAtIndex:section]] count];
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { 
    return (tableView == self.searchDisplayController.searchResultsTableView) ? [[NSArray alloc] initWithObjects:nil] : listIndex;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 
    return (tableView == self.searchDisplayController.searchResultsTableView) ? @"" : [listIndex objectAtIndex:section];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *kCellID = @"cellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellID] autorelease];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

    NSString * name = nil;

    // TODO: Make dataForRowAtIndexPath work here
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        // NOTE: dataForRowAtIndexPath causes this to crash for some unknown reason. Maybe it is called before viewDidLoad and has no data?
        name = [[filteredList objectAtIndex:indexPath.row] objectForKey:@"name"];
    } else {
        // This always works
        name = [self tableView:[self tableView] dataForRowAtIndexPath:indexPath withKey:@"name"];
    }

    cell.textLabel.text = name;

    return cell;
}


#pragma mark Search Methods


- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
    // Clear the filtered array
    [self.filteredList removeAllObjects];

    // Filter the array
    for (NSDictionary *item in fullList) {
        // Compare the item's name to the search text
        NSComparisonResult result = [[item objectForKey:@"name"] compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
        if (result == NSOrderedSame) {
            // Add to the filtered array if it matches
            [self.filteredList addObject:item];
        }
    }
}


- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    [self filterContentForSearchText:searchString scope: [[self.searchDisplayController.searchBar scopeButtonTitles] 
            objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}


- (void)viewDidUnload { filteredList = nil; }


@end

I am having an odd problem when searching a UITableView using a UISearchDisplayController. The UITableViewController is a subclass of another UITableViewController with a working didSelectRowAtIndexPath method. Without searching the controller handles selections fine, sending the superclass a didSelectRowAtIndexPath call, but if I select a cell when searching the superclass receives nothing but the cell is highlighted. Below is the code from my subclass.

@implementation AdvancedViewController


@synthesize searchDisplayController, dict, filteredList;


- (void)viewDidLoad {
    [super viewDidLoad];

    // Programmatically set up search bar
    UISearchBar *mySearchBar = [[UISearchBar alloc] init];
    mySearchBar.delegate = self;
    [mySearchBar setAutocapitalizationType:UITextAutocapitalizationTypeNone];
    [mySearchBar sizeToFit];
    self.tableView.tableHeaderView = mySearchBar;

    // Programmatically set up search display controller
    searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:mySearchBar contentsController:self];
    [self setSearchDisplayController:searchDisplayController];
    [searchDisplayController setDelegate:self];
    [searchDisplayController setSearchResultsDataSource:self];

    // Parse data from server
    NSData * jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
    NSArray * items = [[NSArray alloc] initWithArray:[[CJSONDeserializer deserializer] deserializeAsArray:jsonData error:nil]];

    // Init variables
    dict = [[NSMutableDictionary alloc] init];
    listIndex = [[NSMutableArray alloc] init];
    fullList = [[NSMutableArray alloc] init];
    filteredList = [[NSMutableArray alloc] init];

    // Get each item and format it for the UI
    for(NSMutableArray * item in items) {
        // Get the first letter
        NSString * firstKey = [[[item objectAtIndex:0] substringWithRange:NSMakeRange(0,1)] uppercaseString];

        // Put symbols and numbers in the same section
        if ([[firstKey stringByTrimmingCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]] isEqualToString:@""]) firstKey = @"#";

        // If there isn't a section with this key
        if (![listIndex containsObject:firstKey]) {
            // Add the key to the index for faster access (because it's already sorted)
            [listIndex addObject:firstKey];
            // Add the key to the unordered dictionary
            [dict setObject:[NSMutableArray array] forKey:firstKey];
        }
        // Add the object to the dictionary
        [[dict objectForKey:firstKey] addObject:[[NSMutableDictionary alloc] initWithObjects:item forKeys:[NSArray arrayWithObjects:@"name", @"url", nil]]];
        // Add the object to the list for simple searching
        [fullList addObject:[[NSMutableDictionary alloc] initWithObjects:item forKeys:[NSArray arrayWithObjects:@"name", @"url", nil]]];
    }

    filteredList = [NSMutableArray arrayWithCapacity:[fullList count]];
}


#pragma mark -
#pragma mark Table view data source

// Custom method for object oriented data access
- (NSString *)tableView:(UITableView *)tableView dataForRowAtIndexPath:(NSIndexPath *)indexPath withKey:(NSString *)key {
    return (NSString *)((tableView == self.searchDisplayController.searchResultsTableView) ? 
                        [[filteredList objectAtIndex:indexPath.row] objectForKey:key] :
                        [[[dict objectForKey:[listIndex objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row] valueForKey:key]);
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return (tableView == self.searchDisplayController.searchResultsTableView) ? 1 : (([listIndex count] > 0) ? [[dict allKeys] count] : 1);
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return (tableView == self.searchDisplayController.searchResultsTableView) ? [filteredList count] : [[dict objectForKey:[listIndex objectAtIndex:section]] count];
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { 
    return (tableView == self.searchDisplayController.searchResultsTableView) ? [[NSArray alloc] initWithObjects:nil] : listIndex;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 
    return (tableView == self.searchDisplayController.searchResultsTableView) ? @"" : [listIndex objectAtIndex:section];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *kCellID = @"cellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellID] autorelease];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

    NSString * name = nil;

    // TODO: Make dataForRowAtIndexPath work here
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        // NOTE: dataForRowAtIndexPath causes this to crash for some unknown reason. Maybe it is called before viewDidLoad and has no data?
        name = [[filteredList objectAtIndex:indexPath.row] objectForKey:@"name"];
    } else {
        // This always works
        name = [self tableView:[self tableView] dataForRowAtIndexPath:indexPath withKey:@"name"];
    }

    cell.textLabel.text = name;

    return cell;
}


#pragma mark Search Methods


- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
    // Clear the filtered array
    [self.filteredList removeAllObjects];

    // Filter the array
    for (NSDictionary *item in fullList) {
        // Compare the item's name to the search text
        NSComparisonResult result = [[item objectForKey:@"name"] compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
        if (result == NSOrderedSame) {
            // Add to the filtered array if it matches
            [self.filteredList addObject:item];
        }
    }
}


- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    [self filterContentForSearchText:searchString scope: [[self.searchDisplayController.searchBar scopeButtonTitles] 
            objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}


- (void)viewDidUnload { filteredList = nil; }


@end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏雨凉 2024-09-09 02:02:37

同样的问题发生在我身上,我和你犯了同样的错误。忘记添加 searchResultsDelegate。我的问题是通过更改如下代码解决的:

添加

[searchDisplayController setSearchResultsDelegate:self];

在下面

[searchDisplayController setDelegate:self];
[searchDisplayController setSearchResultsDataSource:self];

Same problem happened to me, i did same mistake with you. Forgot to add searchResultsDelegate. My problem is solved by changing code like below:

add

[searchDisplayController setSearchResultsDelegate:self];

below

[searchDisplayController setDelegate:self];
[searchDisplayController setSearchResultsDataSource:self];
〗斷ホ乔殘χμё〖 2024-09-09 02:02:37

我的建议是在视图控制器中保留一个名为 currentTableViewUITableView 属性。当搜索字段文本更改时,我们设置此属性的值:

- (BOOL) searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString searchScope:(NSInteger)searchOption {
    ...
    if ([[searchString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length])
        self.currentTableView = searchDisplayController.searchResultsTableView;
    else
        self.currentTableView = tableView;
    ...
}

所有其他方法都可以测试 currentTableView 是搜索结果表视图还是“普通”表视图。获取的结果控制器可以与 currentTableView 一起使用,无论它位于哪个上下文中。等等。

My advice is to keep a UITableView property in your view controller called currentTableView. When the search field text changes, we set this property's value:

- (BOOL) searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString searchScope:(NSInteger)searchOption {
    ...
    if ([[searchString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length])
        self.currentTableView = searchDisplayController.searchResultsTableView;
    else
        self.currentTableView = tableView;
    ...
}

All the other methods can test whether currentTableView is a search results table view or a "normal" table view. The fetched results controller can work with currentTableView regardless of which context it is in. Etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文