带有tableview和搜索功能的iOS App

Posted

技术标签:

【中文标题】带有tableview和搜索功能的iOS App【英文标题】:iOS App with tableview and search function 【发布时间】:2013-11-23 01:59:33 【问题描述】:

我正在编写一个 ios 应用程序(来自 iOS 教程的更新应用程序)。它有一个带有 UITableView 和 UISearchBar 的视图(感谢 Ayan 和 Tommy)。我现在的问题是,该表显示来自核心数据实体的所有记录,当我点击一个单元格时,该应用程序会显示来自所选单元格的详细视图。这很好用。问题是使用搜索方法后,如果我点击搜索结果单元格,应用程序不会显示所选单元格的详细视图。我想我必须在任何地方确定搜索记录的发件人,但不知道如何或在哪里包括这个。 这是我目前的代码,欢迎任何帮助或提示...谢谢

#import "PersonsTVC.h"
#import "Person.h"

@implementation PersonsTVC
@synthesize fetchedResultsController = __fetchedResultsController;
@synthesize managedObjectContext = __managedObjectContext;
@synthesize selectedPerson;
@synthesize searchResults;

- (void)setupFetchedResultsController


    NSString *entityName = @"Person";
    NSLog(@"Setting up a Fetched Results Controller for the Entity named %@", entityName);


    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];

    request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"firstname"
                                                                                     ascending:YES
                                                                                      selector:@selector(localizedCaseInsensitiveCompare:)]];

    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                        managedObjectContext:self.managedObjectContext
                                                                          sectionNameKeyPath:nil
                                                                                   cacheName:nil];
    [self performFetch];




- (void) viewDidLoad

    self.searchResults = [NSMutableArray arrayWithCapacity:[[self.fetchedResultsController fetchedObjects] count]];
    [self.tableView reloadData];

-(void) viewDidUnload
    self.searchResults = nil;




- (void)viewWillAppear:(BOOL)animated

    [super viewWillAppear:animated];
    [self setupFetchedResultsController];

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    static NSString *CellIdentifier = @"Persons Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    

    // Configure the cell...
    // Configure the cell...
    Person  *person = nil;

    if (tableView == self.searchDisplayController.searchResultsTableView)
    
        NSLog(@"Configuring cell to show search results");
        person = [self.searchResults objectAtIndex:indexPath.row];
    
    else
    
        NSLog(@"Configuring cell to show normal data");
        person = [self.fetchedResultsController objectAtIndexPath:indexPath];
    








    NSString *fullname = [NSString stringWithFormat:@"%@ %@", person.firstname, person.surname];
    cell.textLabel.text = person.firstname;
    if ([person.inRole.color isEqual :@"Yellow"])
    
        cell.imageView.image = [UIImage imageNamed:@"Yellow"];
    
    if ([person.inRole.color isEqual :@"Black"])
    
        cell.imageView.image = [UIImage imageNamed:@"Black"];
    
    if ([person.inRole.color isEqual :@"Grey"])
    
        cell.imageView.image = [UIImage imageNamed:@"Grey"];
    
    if ([person.inRole.color isEqual :@"Red"])
    
        cell.imageView.image = [UIImage imageNamed:@"Red"];
    
    if ([person.inRole.color isEqual :@"Blue"])
    
        cell.imageView.image = [UIImage imageNamed:@"Blue"];
    
    if ([person.inRole.color isEqual :@"Dark Green"])
    
        cell.imageView.image = [UIImage imageNamed:@"DarkGreen"];
    
    if ([person.inRole.color isEqual :@"Light Green"])
    
        cell.imageView.image = [UIImage imageNamed:@"LightGreen"];
    
    if ([person.inRole.color isEqual :@"Light Blue"])
    
        cell.imageView.image = [UIImage imageNamed:@"LightBlue"];
    
    if ([person.inRole.color isEqual :@"Brown"])
    
        cell.imageView.image = [UIImage imageNamed:@"Brown"];
    
    if ([person.inRole.color isEqual :@"Dark Orange"])
    
        cell.imageView.image = [UIImage imageNamed:@"DarkOrange"];
    
    cell.detailTextLabel.text = person.surname;
    //cell.textLabel.text = person.firstname;
    return cell;



- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    if (tableView == self.searchDisplayController.searchResultsTableView)
    
        return [self.searchResults count];
    
    else
    
        return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
    



- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 

    if (editingStyle == UITableViewCellEditingStyleDelete) 

        [self.tableView beginUpdates]; // Avoid  NSInternalInconsistencyException

        // Delete the person object that was swiped
        Person *personToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
        NSLog(@"Deleting (%@)", personToDelete.firstname);
        [self.managedObjectContext deleteObject:personToDelete];
        [self.managedObjectContext save:nil];

        // Delete the (now empty) row on the table
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [self performFetch];

        [self.tableView endUpdates];
    


- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    if ([segue.identifier isEqualToString:@"Add Person Segue"])
    
        NSLog(@"Setting PersonsTVC as a delegate of PersonDetailTVC");
        PersonDetailTVC *personDetailTVC = segue.destinationViewController;
        personDetailTVC.delegate = self;

        NSLog(@"Creating a new person and passing it to PersonDetailTVC");
        Person *newPerson = [NSEntityDescription insertNewObjectForEntityForName:@"Person"
                                                          inManagedObjectContext:self.managedObjectContext];

        personDetailTVC.person = newPerson; 
    
    else if ([segue.identifier isEqualToString:@"Person Detail Segue"])
    
        NSLog(@"Setting PersonsTVC as a delegate of PersonDetailTVC");
        PersonDetailTVC *personDetailTVC = segue.destinationViewController;
        personDetailTVC.delegate = self;

        // Store selected Person in selectedPerson property
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        self.selectedPerson = [self.fetchedResultsController objectAtIndexPath:indexPath];

        NSLog(@"Passing selected person (%@) to PersonDetailTVC", self.selectedPerson.firstname);
        personDetailTVC.person = self.selectedPerson;
    
    else 
        NSLog(@"Unidentified Segue Attempted!");
    


- (void)theSaveButtonOnThePersonDetailTVCWasTapped:(PersonDetailTVC *)controller

    // do something here like refreshing the table or whatever

    // close the delegated view
    [controller.navigationController popViewControllerAnimated:YES];    


#pragma mark -
#pragma mark Content Filtering

-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope 
    self.searchResults = [[self.fetchedResultsController fetchedObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) 
        Person* person = evaluatedObject;
        NSString* firstName = person.firstname;

        //searchText having length < 3 should not be considered
        if (!!searchText && [searchText length] < 3) 
            return YES;
        

        if ([scope isEqualToString:@"All"] || [firstName isEqualToString:scope])  
            return ([firstName rangeOfString:searchText].location != NSNotFound);
        
        return NO; //if nothing matches
    ]];


#pragma mark -
#pragma mark UISearchDisplayController Delegate Methods

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString

    [self filterContentForSearchText:searchString scope:@"All"];
    return YES;


- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption

    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:@"All"];
    return YES;




@end

【问题讨论】:

请关注tutorial,特别是“将数据发送到详细视图”部分。但是,在发布此类查询之前,请确保您已经进行了足够的研究,否则只会增加网站负担,您的问题将被否决并依次删除。 我看过推荐的教程,但是我没有找到解决我的问题的方法,我看到在推荐的教程中有两个表格视图,而在我的应用程序中只有一个和两个不同的数组,一个用于包含所有记录的普通视图,一个用于过滤记录。对不起,我需要一点帮助... 好的,你的想法。我的建议是始终使用过滤后的结果集作为表的数据源。过滤后的结果集将根据您可能已经弄清楚的搜索过滤器进行过滤。然后在您的cellForRowAtIndexPath 方法中删除检查if (tableView == self.searchDisplayController.searchResultsTableView) 并始终使用person = [self.searchResults objectAtIndex:indexPath.row]; 谢谢 Ayan,但您的建议无效。无论如何谢谢你。你对我很好…… 【参考方案1】:

我猜您的故事板中有一个 segue 设置(您可以在其中按住 Control 单击从表格单元格拖动到详细视图控制器),允许触摸常规表格视图单元格以转到详细信息视图,但是您的搜索表格视图单元格没有明确说明触摸时的操作。

尝试添加表格视图委托方法 didSelectRowAtIndexPath 并在触摸搜索表格单元格时启动 segue:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath


    // Perform segue to detail when a SEARCH table cell is touched
    if(tableView == self.searchDisplayController.searchResultsTableView)
    
        [self performSegueWithIdentifier:@"Person Detail Segue" sender:tableView];
    


这样做应该会在触摸搜索结果表格单元格时触发您的 prepareForSegue 方法。看来您已经实现了处理“Person Detail Segue”的逻辑,但我们需要添加逻辑来区分 segue 是来自选定的常规表格单元格还是来自搜索表格单元格。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    if ([segue.identifier isEqualToString:@"Add Person Segue"])
    
        NSLog(@"Setting PersonsTVC as a delegate of PersonDetailTVC");
        PersonDetailTVC *personDetailTVC = segue.destinationViewController;
        personDetailTVC.delegate = self;

        NSLog(@"Creating a new person and passing it to PersonDetailTVC");
        Person *newPerson = [NSEntityDescription insertNewObjectForEntityForName:@"Person"
                                                        inManagedObjectContext:self.managedObjectContext];

        personDetailTVC.person = newPerson; 
    
    else if ([segue.identifier isEqualToString:@"Person Detail Segue"])
    
        NSLog(@"Setting PersonsTVC as a delegate of PersonDetailTVC");
        PersonDetailTVC *personDetailTVC = segue.destinationViewController;
        personDetailTVC.delegate = self;

        // Store selected Person in selectedPerson property
        if(sender == self.searchDisplayController.searchResultsTableView)
        
            NSIndexPath *indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
            self.selectedPerson = [self.searchResults objectAtIndex:[indexPath row]];
        
        else
        
            NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
            self.selectedPerson = [self.fetchedResultsController objectAtIndexPath:indexPath];
        

        NSLog(@"Passing selected person (%@) to PersonDetailTVC",    self.selectedPerson.firstname);
        personDetailTVC.person = self.selectedPerson;
    
    else
    
        NSLog(@"Unidentified Segue Attempted!");
    

我可能存在一些实施错误,但我相信这是对您有用的一般策略。我希望这会有所帮助。

【讨论】:

谢谢 Mfarmer,您的解决方案运行良好,非常好的解决方案。我从你的代码中学到了很多东西。

以上是关于带有tableview和搜索功能的iOS App的主要内容,如果未能解决你的问题,请参考以下文章

双击需要使用搜索栏选择 TableView 项目

如何在iOS中删除UITableViewCell的No Result TableView?

带有静态 TableView 单元的 IOS 8 动态类型 - 基本和字幕

iOS中tableview中的动态搜索

带有核心数据的 TableView 中的搜索栏(使用 Swift)

从 iOS 11 搜索控制器导航时不需要的 UITableView 重新加载动画