My app crashes if I do this:
-
I make a search on my UITableView
-
After a search I tap on UITableViewCell of
searchDisplayControllerUITableView and go to another View Controller -
I then come back to the main UITableView,
questionTable– the one in which I searched, and tap on the last cell, or any cell that is greater then the number of search results I previously had. -
App crashes with this error:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 12 beyond bounds [0 .. 0]' *** First throw call stack:(0x35aa188f 0x37e48259 0x359ea9db 0x155fd 0x3384df5b 0x153ed 0x3358793d 0x33601627 0x355bb933 0x35a75a33 0x35a75699 0x35a7426f 0x359f74a5 0x359f736d 0x37693439 0x33503cd5 0x95a3 0x9548) terminate called throwing an exception(lldb)
I suspect the problem is with my code, because searching UITableView is a new topic for me. That’s how I do it:
1.My VC conforms to these protocols <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate>
2.I have these variables:
@property (nonatomic, retain) NSMutableArray *searchResults;
@property (nonatomic, copy) NSString *savedSearchTerm;
3. In viewDidLoad i set up the source of my UITableView which I search:
self.questionList = [[NSArray alloc]
initWithObjects: MY OBJECTS HERE, nil];
if ([self savedSearchTerm])
{
[[[self searchDisplayController] searchBar] setText:[self savedSearchTerm]];
}
4. I have this action to handle the search:
- (void)handleSearchForTerm:(NSString *)searchTerm
{
[self setSavedSearchTerm:searchTerm];
if ([self searchResults] == nil)
{
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
}
[[self searchResults] removeAllObjects];
if ([[self savedSearchTerm] length] != 0)
{
for (NSString *currentString in [self questionList])
{
if ([currentString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
{
[[self searchResults] addObject:currentString];
}
}
}
}
5) Here’s how I set up my UITable views:
(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = [indexPath row];
NSString *contentForThisRow = nil;
if (tableView == [[self searchDisplayController] searchResultsTableView])
contentForThisRow = [[self searchResults] objectAtIndex:row];
else
contentForThisRow = [[self questionList] objectAtIndex:row];
static NSString *CellIdentifier = @"questionsCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[[cell textLabel] setText:contentForThisRow];
return cell;
}
6) Here’s how my numberOfRowsInSection method looks like:
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger rows;
if (tableView == [[self searchDisplayController] searchResultsTableView])
rows = [[self searchResults] count];
else
rows = [[self questionList] count];
return rows;
}
7) Finally, I have these two methods:
(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self handleSearchForTerm:searchString];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
(void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
[self setSavedSearchTerm:nil];
[[self questionTable] reloadData];
}
I’m really sorry for the long question. I have made some mistake in the code and I hope someone could show me the right way to do this. The Search Bar Controller is properly linked in the IB
Any help would be highly appreciated!
NEW EDIT:
I’m pushing a new VC on didSelectRowAtIndePath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:@"toAnswer" sender:indexPath];
}
And I’m updating an NSString there. It worked perfectly when I used just one TableView
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
((QandADetailsViewController *)segue.destinationViewController).delegate=self;
NSIndexPath *indexPath = (NSIndexPath *)sender;
QandADetailsViewController *mdvc = segue.destinationViewController;
if (self.searchResults == nil) {
mdvc.questionName = [self.questionList
objectAtIndex:indexPath.row];
} else {
mdvc.questionName = [self.searchResults
objectAtIndex:indexPath.row];
}
}
In prepare for segue, the check for searchResults == nil is probably incorrect. There’s no reason to expect it to be nil ever after the first search. That means you’ll always be dereferencing the search array on subsequent table selections, explaining the index out of bounds.
The fix, I think, is to ask
if ([self.searchDisplayController isActive])instead of whether search results exist.