Ios 表视图部分中的搜索结果对象不应有的行为

Ios 表视图部分中的搜索结果对象不应有的行为,ios,uitableview,core-data,uisearchbar,Ios,Uitableview,Core Data,Uisearchbar,我有一个带有节的UITableView。每个核心数据对象显示在预期部分下。为了测试应用程序,我添加了3个对象 1. item 2(overdue)-> OVERDUE section 2. item 1(today)-> TODAY section 3. item 3(upcoming)->UPCOMING section. 我还实现了一个搜索栏,它通过属性todoName过滤对象(只需要匹配3个字符)。 这是应用程序第一个视图中的屏幕截图: 如果我在搜索栏控制器中引入搜索

我有一个带有节的
UITableView
。每个
核心数据对象
显示在预期部分下。为了测试应用程序,我添加了3个对象

1. item 2(overdue)-> OVERDUE section
2. item 1(today)-> TODAY section
3. item 3(upcoming)->UPCOMING section.
我还实现了一个
搜索栏
,它通过属性todoName过滤对象(只需要匹配3个字符)。 这是应用程序第一个视图中的屏幕截图:

如果我在搜索栏控制器中引入搜索字符串,结果对象将重复显示,并显示在所有部分下。搜索“day”后,请参见下面的示例

以下是我的问题:

1。我需要结果对象可以显示在其上一节下,也可以不显示在任何节下,但不能显示在所有节下

2.结果对象失去了右>符号,点击时不提供任何操作

欢迎任何建议或帮助。 以下是我目前的代码:

#import "ToDoItemsTableViewController.h"
#import "AppDelegate.h"
#import "AddToDoItemViewController.h"
#import "ToDoSubItemsTableViewController.h"

@interface ToDoItemsTableViewController ()

@property (nonatomic, strong)NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong)NSFetchedResultsController *fetchedResultsController;

@end

@implementation ToDoItemsTableViewController
@synthesize searchResults;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}
-(NSManagedObjectContext *)managedObjectContext{
    return [(AppDelegate*)[[UIApplication sharedApplication]delegate]managedObjectContext];
}
- (void)viewDidLoad
{
    [super viewDidLoad];


    //navigation bar background image
    [self.navigationController.navigationBar

     setBackgroundImage:[UIImage imageNamed:@"navBar.png"]

     forBarMetrics:UIBarMetricsDefault];

    NSDictionary *textAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [UIColor blackColor],NSForegroundColorAttributeName,
                                    [UIColor blackColor],NSBackgroundColorAttributeName,nil];
    self.navigationController.navigationBar.titleTextAttributes = textAttributes;



    NSError *error = nil;
    if (![[self fetchedResultsController]performFetch:&error]){
        NSLog(@"Error %@",error);
        abort();
    }
    self.searchResults = [NSMutableArray arrayWithCapacity:[[self.fetchedResultsController fetchedObjects] count]];
    [self.tableView reloadData];
}
-(void) viewWillAppear:(BOOL)animated{
    [self.tableView reloadData];
}
- (void)viewDidUnload
{
    self.searchResults = nil;
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

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

    if ([[segue identifier]isEqualToString:@"addToDoItem"]){
        UINavigationController *navigationController = segue.destinationViewController;

        AddToDoItemViewController *addToDoItemViewController = (AddToDoItemViewController*)navigationController.topViewController;
        ToDoItem *addToDoItem = [NSEntityDescription insertNewObjectForEntityForName:@"ToDoItem" inManagedObjectContext:self.managedObjectContext];
        addToDoItem.todoDueDate = [NSDate date];
        addToDoItemViewController.addToDoItem = addToDoItem;
    }
    if ([[segue identifier] isEqualToString:@"toToDoSubItems"]){

        ToDoSubItemsTableViewController *todoSubItemsTableViewController = [segue destinationViewController];
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        ToDoItem *selectedToDoItem = (ToDoItem*)[self.fetchedResultsController objectAtIndexPath:indexPath];
        todoSubItemsTableViewController.selectedToDoItem = selectedToDoItem;



    }




}



#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    return [[self.fetchedResultsController sections]count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (tableView == self.searchDisplayController.searchResultsTableView)
    {
        return [self.searchResults count];
    }
    else {
    id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections]objectAtIndex:section];
    return [sectionInfo numberOfObjects];

    }
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    // Configure the cell...

    ToDoItem *toDoItem = nil;



    if (tableView == self.searchDisplayController.searchResultsTableView)
    {
        if (cell==nil) {
            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

        }
        NSLog(@"Configuring cell to show search results");
        toDoItem = [self.searchResults objectAtIndex:indexPath.row];
        cell.textLabel.text = toDoItem.todoName;



        NSDate *fechaToDO = toDoItem.todoDueDate;

        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
        [dateFormatter setDateFormat:@"EEEE, dd MMMM YYYY"];
        NSString *fechaToDo = [dateFormatter stringFromDate:fechaToDO];



        cell.detailTextLabel.text = fechaToDo;

    }
    else
    {


    ToDoItem *todoItem = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = todoItem.todoName;



    NSDate *fechaToDO = todoItem.todoDueDate;

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
    [dateFormatter setDateFormat:@"EEEE, dd MMMM YYYY"];
    NSString *fechaToDo = [dateFormatter stringFromDate:fechaToDO];



    cell.detailTextLabel.text = fechaToDo;
    }
    return cell;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *header = @"customHeader";

    UITableViewHeaderFooterView *vHeader;

    vHeader = [tableView dequeueReusableHeaderFooterViewWithIdentifier:header];

    if (!vHeader) {
        vHeader = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:header];
        vHeader.textLabel.backgroundColor = [UIColor redColor];
        vHeader.textLabel.textColor = [UIColor whiteColor];

        vHeader.contentView.backgroundColor = [UIColor redColor];
    }

    if (section == 0) {
        vHeader.textLabel.backgroundColor = [UIColor redColor];
        vHeader.textLabel.textColor = [UIColor whiteColor];

        vHeader.contentView.backgroundColor = [UIColor redColor];
    }

    else if (section == 1) {
        vHeader.textLabel.backgroundColor = [UIColor orangeColor];
        vHeader.textLabel.textColor = [UIColor blueColor];

        vHeader.contentView.backgroundColor = [UIColor orangeColor];
    }
    else if (section == 2) {
        vHeader.textLabel.backgroundColor = [UIColor greenColor];
        vHeader.textLabel.textColor = [UIColor whiteColor];

        vHeader.contentView.backgroundColor = [UIColor greenColor];
    }


    vHeader.textLabel.text = [self tableView:tableView titleForHeaderInSection:section];

    return vHeader;
}
-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{




    id <NSFetchedResultsSectionInfo> theSection = [[self.fetchedResultsController sections]objectAtIndex:section];
    NSString *sectionname = [theSection name];

    if ([sectionname isEqualToString:@"0"]){

        NSString *valor = [NSString stringWithFormat:@"O V E R D U E   (%d)", [self.tableView
                                                             numberOfRowsInSection:section]];
        return valor;
    }
    else if ([sectionname isEqualToString:@"1"]){

        NSString *valor = [NSString stringWithFormat:@"T O D A Y   (%d)", [self.tableView
                                           numberOfRowsInSection:section]];
        return valor;
    }
    else if ([sectionname isEqualToString:@"2"]){

        NSString *valor = [NSString stringWithFormat:@"U P C O M I N G   (%d)", [self.tableView
                                                             numberOfRowsInSection:section]];
        return valor;
    }




    if ([[self.fetchedResultsController sections]count]>0){
        id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections]objectAtIndex:section];
        return [sectionInfo name];
    }
    else{
        return nil;
    }

}


#pragma mark - Fetched Results Controller Section

-(NSFetchedResultsController*)fetchedResultsController{

    if (_fetchedResultsController != nil){
        return _fetchedResultsController;
    }
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
    NSManagedObjectContext *context = self.managedObjectContext;
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"ToDoItem" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey:@"todoDueDate" ascending:YES];
    NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc]initWithKey:@"todoName" ascending:YES];

    NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:sortDescriptor,sortDescriptor1, nil];
    fetchRequest.sortDescriptors = sortDescriptors;
    _fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:@"sectionIdentifier" cacheName:nil];
    _fetchedResultsController.delegate = self;
    return _fetchedResultsController;
}


#pragma mark - Fetched Results Controller Delegates

-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];

}

-(void) controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath{

    UITableView *tableView = self.tableView;

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeUpdate:{

            ToDoItem *changeToDoItem = [self.fetchedResultsController objectAtIndexPath:indexPath];
            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
            cell.textLabel.text = changeToDoItem.todoName;
            NSDate *fechaToDO = changeToDoItem.todoDueDate;

            NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
            [dateFormatter setDateFormat:@"EEEE, dd MMMM YYYY"];
            NSString *fechaToDo = [dateFormatter stringFromDate:fechaToDO];
            cell.detailTextLabel.text = fechaToDo;
        }
            break;
        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }


}

-(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type{

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }

}





/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the specified item to be editable.
    return YES;
}
*/


// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        NSManagedObjectContext *context = [self managedObjectContext];
        ToDoItem *ToDoItemToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
        [context deleteObject:ToDoItemToDelete];


        NSError *error = nil;
        if (![context save:&error]){
            NSLog(@"Error: %@",error);
        }

    }
}


/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/

/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the item to be re-orderable.
    return YES;
}
*/

/*
#pragma mark - Navigation

// In a story board-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}

 */
#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) {
        ToDoItem * item = evaluatedObject;
        NSString* name = item.todoName;

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

        if ([scope isEqualToString:@"All"] || [name isEqualToString:scope])  {
            return ([name 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
但在尝试删除搜索结果对象时,应用程序显示以下异常:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
*** First throw call stack:
请检查我更改的方法以检测问题所在,谢谢


这里是完整的异常,可能有助于您检测问题:

[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x89be750
2014-01-16 22:54:08.530 To-Do Pro Light[2319:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x89be750'
*** First throw call stack:
(
    0   CoreFoundation                      0x01aab5e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x0182e8b6 objc_exception_throw + 44
    2   CoreFoundation                      0x01b48903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
    3   CoreFoundation                      0x01a9b90b ___forwarding___ + 1019
    4   CoreFoundation                      0x01a9b4ee _CF_forwarding_prep_0 + 14
    5   To-Do Pro Light                     0x00004eda -[ToDoItemsTableViewController tableView:commitEditingStyle:forRowAtIndexPath:] + 298
    6   UIKit                               0x0068cba3 -[UITableView animateDeletionOfRowWithCell:] + 107
    7   UIKit                               0x0080c695 -[UITableViewCell _swipeDeleteButtonPushed] + 70
    8   libobjc.A.dylib                     0x01840874 -[NSObject performSelector:withObject:withObject:] + 77
    9   UIKit                               0x0059e0c2 -[UIApplication sendAction:to:from:forEvent:] + 108
    10  UIKit                               0x0059e04e -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
    11  UIKit                               0x006960c1 -[UIControl sendAction:to:forEvent:] + 66
    12  UIKit                               0x00696484 -[UIControl _sendActionsForEvents:withEvent:] + 577
    13  UIKit                               0x00695733 -[UIControl touchesEnded:withEvent:] + 641
    14  UIKit                               0x00910c7f _UIGestureRecognizerUpdate + 7166
    15  UIKit                               0x005db19a -[UIWindow _sendGesturesForEvent:] + 1291
    16  UIKit                               0x005dc0ba -[UIWindow sendEvent:] + 1030
    17  UIKit                               0x005afe86 -[UIApplication sendEvent:] + 242
    18  UIKit                               0x0059a18f _UIApplicationHandleEventQueue + 11421
    19  CoreFoundation                      0x01a3483f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
    20  CoreFoundation                      0x01a341cb __CFRunLoopDoSources0 + 235
    21  CoreFoundation                      0x01a5129e __CFRunLoopRun + 910
    22  CoreFoundation                      0x01a50ac3 CFRunLoopRunSpecific + 467
    23  CoreFoundation                      0x01a508db CFRunLoopRunInMode + 123
    24  GraphicsServices                    0x038bc9e2 GSEventRunModal + 192
    25  GraphicsServices                    0x038bc809 GSEventRun + 104
    26  UIKit                               0x0059cd3b UIApplicationMain + 1225
    27  To-Do Pro Light                     0x00007d2d main + 141
    28  libdyld.dylib                       0x020e7725 start + 0
)
libc++abi.dylib: terminating with uncaught exception of type NSException

您需要将
numberOfSectionsInTableView:
更改为

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    if (tableView == self.searchDisplayController.searchResultsTableView)
    {
       return 1;
    }
    else
    { 
       return [[self.fetchedResultsController sections]count];
    }
}
编辑关于崩溃的第二个问题

更改
committeditingstyle:forRowAtIndexPath:
如:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
     if (tableView == self.searchDisplayController.searchResultsTableView)
     {
         [self.searchResults removeObjectAtIndex:indexPath.row];
         [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
     }
     else
     {
         if (editingStyle == UITableViewCellEditingStyleDelete)
         {
             // Delete the row from the data source
             NSManagedObjectContext *context = [self managedObjectContext];
             ToDoItem *ToDoItemToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
             [context deleteObject:ToDoItemToDelete];


              NSError *error = nil;
              if (![context save:&error])
              {
                 NSLog(@"Error: %@",error);
              }
          }
     }
}

@mvasco:您需要在
viewForHeaderInSection
titleForHeaderInSection
@mvasco:您需要使用
if(tableView==self.searchDisplayController.searchResultsTableView)
检查if(tableView==self.searchDisplayController.searchResultsTableView)并从这些方法返回适当的视图和标题。您还可以使用
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicatorarrow@mvasco:对不起,我离线了。您需要实现
didSelectRowAtIndexPath
方法,在此方法中,您需要打开新的视图控制器。@mvasco:我认为没有,因为
searchDisplayController.searchResultsTableView
是动态创建的。它不会使用您在故事板中设计的tableview。@mvasco:如果条件问题相同:)现在将其放在
-(void)tableview:(UITableView*)tableview CommittedItingStyle:(UITableViewCellEditingStyle)editingStyle for RowAtIndexPath:(NSIndexPath*)indexPath上,对于searchDisplayTable,删除不能这样做。您需要使用RowAnimation:UITableViewRowAnimationFade调用
tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
     if (tableView == self.searchDisplayController.searchResultsTableView)
     {
         [self.searchResults removeObjectAtIndex:indexPath.row];
         [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
     }
     else
     {
         if (editingStyle == UITableViewCellEditingStyleDelete)
         {
             // Delete the row from the data source
             NSManagedObjectContext *context = [self managedObjectContext];
             ToDoItem *ToDoItemToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
             [context deleteObject:ToDoItemToDelete];


              NSError *error = nil;
              if (![context save:&error])
              {
                 NSLog(@"Error: %@",error);
              }
          }
     }
}