带有 Section、IndexList 和 Search 的 UITableView

Posted

技术标签:

【中文标题】带有 Section、IndexList 和 Search 的 UITableView【英文标题】:UITableView with Section, IndexList and Search 【发布时间】:2018-08-22 19:41:48 【问题描述】:

我已经添加了我的委托方法和

我有一个带有名称列表的 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

【问题讨论】:

您需要更新您的问题以包含相关的表格视图数据源和驱动搜索结果控制器的委托方法。 感谢您的澄清。我已经添加了输入标头和实现。 【参考方案1】:

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

[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

尝试并分享您的结果。

【讨论】:

有帮助吗?你能解决这个问题吗?

以上是关于带有 Section、IndexList 和 Search 的 UITableView的主要内容,如果未能解决你的问题,请参考以下文章

Section 1.1

MITG2102 Mobile Computing (Section 51)

git configuration

1 谈谈section标签

div,section,article的区别和使用

删除 Hive SQL 查询中两个子字符串之间的所有字符