首页 > 解决方案 > 带有 Section、IndexList 和 Search 的 UITableView

问题描述

我添加了我的委托方法和

我有一个带有名称列表的 UITableView。它的右侧有字母索引的部分(见图)。

在此处输入图像描述

每当我在搜索字段中输入第一个字符时,我的程序就会崩溃。我收到以下错误:

UpdateSearchResultsForSearchController
[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'

了解我正在尝试在 UpdateSearchResultsForSearchController 方法中访问一个空数组。

程序在方法的最后一行崩溃。

 [((UITableViewController *)self.searchController.searchResultsController).tableView reloadData];

这是标题

#import <UIKit/UIKit.h>
#import "EmployeeDatabase.h"

@interface EmployeeListViewController : UITableViewController<UISearchResultsUpdating, UISearchBarDelegate>

@property (nonatomic, strong) NSMutableArray *employees;

@property (nonatomic, strong) UISearchController *searchController;

@property (nonatomic, strong) NSMutableArray *tableSections;

@property (nonatomic, strong) NSMutableArray *tableSectionsAndItems;

@end

这是实现

#import "EmployeeListViewController.h"
#import "EmployeeDetailViewController.h"

@implementation EmployeeListViewController

- (void)viewDidLoad {

  [super viewDidLoad];

  [self initializeTableContent];

  [self initializeSearchController];

  [self styleTableView];
}

- (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
}

#pragma mark - Initialization methods

- (void)initializeTableContent {

  self.employees = [EmployeeDatabase getEmployees];
  self.tableSections = [NSMutableArray array];
  self.tableSectionsAndItems = [NSMutableArray array];

  for (employee *name in self.employees) {

    NSString *key =  [[name.lstNme substringToIndex: 1] uppercaseString];

    if ([self.tableSections containsObject:key] == false) {
      [self.tableSections addObject:key];
      NSMutableArray *tmpArray = [NSMutableArray array];
      [tmpArray addObject:name.fulNme];
      NSMutableDictionary *tmpDictionary = [NSMutableDictionary dictionaryWithObject:tmpArray forKey:key];
      [self.tableSectionsAndItems addObject:tmpDictionary];
    } else {
      NSMutableArray *tmpArray = [NSMutableArray array];
      NSUInteger index = [self.tableSections indexOfObject:key];
      NSMutableDictionary *tmpDictionary = [self.tableSectionsAndItems objectAtIndex:index];
      tmpArray = [tmpDictionary objectForKey:key];
      [tmpArray addObject:name.fulNme];
      [self.tableSectionsAndItems removeObjectAtIndex:index];
      [self.tableSectionsAndItems addObject:tmpDictionary];
    }

}

}
- (void)initializeSearchController {

  //instantiate a search results controller for presenting the search/filter results (will be presented on top of the parent table view)
  UITableViewController *searchResultsController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];

  searchResultsController.tableView.dataSource = self;

  searchResultsController.tableView.delegate = self;

  //instantiate a UISearchController - passing in the search results controller table
  self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];

  //this view controller can be covered by theUISearchController's view (i.e. search/filter table)
  self.definesPresentationContext = YES;

  //define the frame for the UISearchController's search bar and tint
  self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x,
                                                     self.searchController.searchBar.frame.origin.y,
                                                     self.searchController.searchBar.frame.size.width, 44.0);

  self.searchController.searchBar.tintColor = [UIColor whiteColor];

  //add the UISearchController's search bar to the header of this table
  self.tableView.tableHeaderView = self.searchController.searchBar;

  //this ViewController will be responsible for implementing UISearchResultsDialog protocol method(s) - so handling what happens when user types into the search bar
  self.searchController.searchResultsUpdater = self;

  //this ViewController will be responsisble for implementing UISearchBarDelegate protocol methods(s)
  self.searchController.searchBar.delegate = self;
}

- (void)styleTableView {

  [[self tableView] setSectionIndexColor:[UIColor colorWithRed:100.0f/255.0f green:100.0f/255.0f blue:100.0f/255.0f alpha:1.0f]];

  [[self tableView] setSectionIndexBackgroundColor:[UIColor colorWithRed:230.0f/255.0f green:230.0f/255.0f blue:230.0f/255.0f alpha:1.0f]];
}

#pragma mark - UITableViewDataSource methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  return [self.tableSections count];
}

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

    NSDictionary *sectionItems = [self.tableSectionsAndItems objectAtIndex:section];
    NSArray *namesForSection = [sectionItems objectForKey:[self.tableSections objectAtIndex:section]];
    return [namesForSection count];

}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return [self.tableSections objectAtIndex:section];
}

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

  static NSString *CellReuseId = @"Cell";
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellReuseId];

  if(cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellReuseId];
  }

  NSDictionary *sectionItems = [self.tableSectionsAndItems objectAtIndex:indexPath.section];
  NSArray *namesForSection = [sectionItems objectForKey:[self.tableSections objectAtIndex:indexPath.section]];
  cell.textLabel.text = [namesForSection objectAtIndex:indexPath.row];

  //show accessory disclosure indicators on cells only when user has typed into the search box
  if(self.searchController.searchBar.text.length > 0) {
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  }

  return cell;
}

#pragma mark - UITableViewDelegate methods

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

  NSDictionary *sectionItems = [self.tableSectionsAndItems objectAtIndex:indexPath.section];
  NSArray *namesForSection = [sectionItems objectForKey:[self.tableSections objectAtIndex:indexPath.section]];
  NSString *selectedItem = [namesForSection objectAtIndex:indexPath.row];

  //Log
  NSLog(@"User selected %@", selectedItem);

}

//#pragma Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"showDetail"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
        employee *employee = self.employees[indexPath.row];
        EmployeeDetailViewController *employeeDetailViewController = segue.destinationViewController;
        employeeDetailViewController.detailItem = employee;
    }

}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {

  //only show section index titles if there is no text in the search bar
  if(!(self.searchController.searchBar.text.length > 0)) {

    NSArray *indexTitles = self.tableSections;
    //HERE
    //*indexTitles = [Item fetchDistinctItemGroupsInManagedObjectContext:self.managedObjectContext];
    return indexTitles;

  } else {

    return nil;
  }
}

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
  view.tintColor = [UIColor colorWithRed:100.0f/255.0f green:100.0f/255.0f blue:100.0f/255.0f alpha:1.0f];
  UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;

  [header.textLabel setTextColor:[UIColor whiteColor]];
}

#pragma mark - UISearchResultsUpdating

-(void)updateSearchResultsForSearchController:(UISearchController *)searchController {

  //get search text from user input
  NSString *searchText = [self.searchController.searchBar text];

  //exit if there is no search text (i.e. user tapped on the search bar and did not enter text yet)
  if(!([searchText length] > 0)) {
    return;
  }
  //handle when there is search text entered by the user
  else {

    //based on the user's search, we will update the contents of the tableSections and tableSectionsAndItems properties
    [self.tableSections removeAllObjects];
    [self.tableSectionsAndItems removeAllObjects];

    NSString *firstSearchCharacter = [searchText substringToIndex:1];

    //handle when user taps into search bear and there is no text entered yet
    if([searchText length] == 0) {
      //self.tableSections = [[Item fetchDistinctItemGroupsInManagedObjectContext:self.managedObjectContext] mutableCopy];
      //self.tableSectionsAndItems = [[Item fetchItemNamesByGroupInManagedObjectContext:self.managedObjectContext] mutableCopy];
    }
    //handle when user types in one or more characters in the search bar
    else if(searchText.length > 0) {

      //the table section will always be based off of the first letter of the group
      NSString *upperCaseFirstSearchCharacter = [firstSearchCharacter uppercaseString];
      self.tableSections = [[[NSArray alloc] initWithObjects:upperCaseFirstSearchCharacter, nil] mutableCopy];

      //there will only be one section (based on the first letter of the search text) - but the property requires an array for cases when there are multiple sections
        //NSDictionary *namesByGroup = [Item fetchItemNamesByGroupFilteredBySearchText:searchText ////inManagedObjectContext:self.managedObjectContext];
         //self.tableSectionsAndItems = [[[NSArray alloc] initWithObjects:namesByGroup, nil] mutableCopy];
    }

    //now that the tableSections and tableSectionsAndItems properties are updated, reload the UISearchController's tableview
    [((UITableViewController *)self.searchController.searchResultsController).tableView reloadData];
  }
}

#pragma mark - UISearchBarDelegate methods

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {

  [self.tableSections removeAllObjects];
  [self.tableSectionsAndItems removeAllObjects];
  //self.tableSections = [[Item fetchDistinctItemGroupsInManagedObjectContext:self.managedObjectContext] mutableCopy];
  //self.tableSectionsAndItems = [[Item fetchItemNamesByGroupInManagedObjectContext:self.managedObjectContext] mutableCopy];

}

@end

标签: iosobjective-cuitableview

解决方案


问题是,您正在删除此行的所有对象

[self.tableSectionsAndItems removeAllObjects];

并且您已经评论了这些行,这再次感觉到该数组,就在您在问题中提到的行之上。所以,取消注释以下行

//NSDictionary *namesByGroup = [Item fetchItemNamesByGroupFilteredBySearchText:searchText ////inManagedObjectContext:self.managedObjectContext];
//self.tableSectionsAndItems = [[[NSArray alloc] initWithObjects:namesByGroup, nil] mutableCopy];

在 numberOfRows 方法中,您正在访问导致崩溃的空数组索引处的对象。

[self.tableSectionsAndItems objectAtIndex:section];

因此,在以下方法中取消注释上面的这两行,它将修复。

-(void)updateSearchResultsForSearchController:(UISearchController *)searchController

尝试并分享您的结果。


推荐阅读