1
votes

I've been following a tutorial to implement a search bar.

However I can't seem to push different views. Here is what my didsSelectRowAtIndexPath looks like.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selectedCountry = nil;

if(searching)
    selectedCountry = [copyListOfItems objectAtIndex:indexPath.row];
else {

    NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
    NSArray *array = [dictionary objectForKey:@"Countries"];
    selectedCountry = [array objectAtIndex:indexPath.row];
}

//Initialize the detail view controller and display it.
if ([[listOfItems  objectAtIndex:indexPath.row] isEqual:@"neon"]){
Neon *abo = [[Neon alloc] initWithNibName:@"Neon" bundle:nil];
//dvController.selectedCountry = selectedCountry;
[self.navigationController pushViewController:abo animated:YES];
[abo release];
}

}

And here is the debuger message when I click on neon: 2010-05-09 08:47:27.516 iTeachU[3821:307] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[NSMutableArray objectAtIndex:]: index 60 beyond bounds [0 .. 0]' *** Call stack at first throw: terminate called after throwing an instance of 'NSException' Program received signal: “SIGABRT”.

If anyone has a way to push views based on the cells text it would be greatly appreciated. Thanks

Edit Entire .m

- (void)viewDidLoad {
[super viewDidLoad];
listOfItems = [[NSMutableArray alloc] init];

NSArray *ElementsArray = [NSArray arrayWithObjects:@"Actinium",
                          @"Aluminium",
                          @"Americium",
                          @"Antimony",
                          @"Argon",
                          @"Arsenic",
                          @"Astatine",
                          @"Barium",
                          @"Berkelium", 
                          @"Beryllium",
                          @"Bismuth",
                          @"Bohrium",
                          @"Boron",
                          @"Bromine",
                          @"Cadmium",
                          @"Cesium",
                          @"Calcium",
                          @"Californium",
                          @"Carbon",
                          @"Cerium",
                          @"Chlorine",
                          @"Chromium",
                          @"Cobalt",
                          @"Copper",
                          @"Curium",
                          @"Darmstadtium",
                          @"Dubnium",
                          @"Dysprosium",
                          @"Einsteinium", 
                          @"Erbium",
                          @"Europium",
                          @"Fermium",
                          @"Fluorine",
                          @"Francium",
                          @"Gadolinium",
                          @"Gallium",
                          @"Germanium",
                          @"Gold",
                          @"Hafnium",
                          @"Hassium",
                          @"Helium",
                          @"Holmium",
                          @"Hydrogen",
                          @"Indium",
                          @"Iodine",
                          @"Iridium",
                          @"Iron",
                          @"Krypton",
                          @"Lanthanum",
                          @"Lawrencium",
                          @"Lead",
                          @"Lithium",
                          @"Lutetium",
                          @"Magnesium",
                          @"Manganese",
                          @"Meitnerium",
                          @"Mendelevium",
                          @"Mercury",
                          @"Molybdenum",
                          @"Neodymium",
                          @"neon",
                          @"Neptunium",
                          @"Nickel", 
                          @"Niobium",
                          @"Nitrogen",
                          @"Nobelium",
                          @"Osmium",
                          @"Oxygen", 
                          @"Palladium",
                          @"Phosphorus",
                          @"Platinum",
                          @"Plutonium",
                          @"Polonium",
                          @"Potassium ",
                          @"Praseodymium",
                          @"Promethium",
                          @"Protactinium", 
                          @"Radium", 
                          @"Radon",
                          @"Rhenium",
                          @"Rhodium",
                          @"Roentgenium",
                          @"Rubidium", 
                          @"Ruthenium",
                          @"Rutherfordium",
                          @"Samarium", 
                          @"Scandium",
                          @"Seaborgium", 
                          @"Selenium",
                          @"Silicon", 
                          @"Silver",
                          @"Sodium", 
                          @"Strontium",
                          @"Sulfur",
                          @"Tantalum",
                          @"Technetium",
                          @"Tellurium",
                          @"Terbium",
                          @"Thallium",
                          @"Thorium",
                          @"Thulium",
                          @"Tin",
                          @"Titanium",
                          @"Tungsten",
                          @"Ununbium",
                          @"Ununhexium",
                          @"Ununoctium",
                          @"Ununpentium",
                          @"Ununquadium", 
                          @"Ununseptium",
                          @"Ununtrium",
                          @"Uranium",
                          @"Vanadium",
                          @"Xenon", 
                          @"Ytterbium",
                          @"Yttrium",
                          @"Zinc",
                          @"Zirconium", nil];
NSDictionary *ElementsDict = [NSDictionary dictionaryWithObject:ElementsArray     forKey:@"Elements"];


[listOfItems addObject:ElementsDict];

//Initialize the copy array.
copyListOfItems = [[NSMutableArray alloc] init];

//Set the title
self.navigationItem.title = @"Elements";

//Add the search bar
self.tableView.tableHeaderView = searchBar;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;

searching = NO;
letUserSelectRow = YES;
}

-(IBAction) back:(id)sender{
[self.navigationController popViewControllerAnimated:NO];   
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}



#pragma mark -
#pragma mark Table view data source

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

if (searching)
    return 1;
else
    return [listOfItems count];
}



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

if (searching)
    return [copyListOfItems count];
else {

    //Number of rows it should expect should be based on the section
    NSDictionary *dictionary = [listOfItems objectAtIndex:section];
    NSArray *array = [dictionary objectForKey:@"Elements"];
    return [array count];
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

if(searching)
    return @"Search Results";

if(section == 0)
    return @"Elements";
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";

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

// Configure the cell...

if(searching) 
    cell.text = [copyListOfItems objectAtIndex:indexPath.row];
else {

    //First get the dictionary object
    NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
    NSArray *array = [dictionary objectForKey:@"Elements"];
    NSString *cellValue = [array objectAtIndex:indexPath.row];
    cell.text = cellValue;
}

return cell;
}

- (NSIndexPath *)tableView :(UITableView *)theTableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {

if(letUserSelectRow)
    return indexPath;
else
    return nil;
}


- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar {

//This method is called again when the user clicks back from teh detail view.
//So the overlay is displayed on the results, which is something we do not want to happen.
if(searching)
    return;

//Add the overlay view.
if(ovController == nil)
    ovController = [[OverlayViewController alloc] initWithNibName:@"OverlayView" bundle:[NSBundle mainBundle]];

CGFloat yaxis = self.navigationController.navigationBar.frame.size.height;
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height;

//Parameters x = origion on x-axis, y = origon on y-axis.
CGRect frame = CGRectMake(0, yaxis, width, height);
ovController.view.frame = frame;    
ovController.view.backgroundColor = [UIColor grayColor];
ovController.view.alpha = 0.5;

ovController.rvController = self;

[self.tableView insertSubview:ovController.view aboveSubview:self.parentViewController.view];

searching = YES;
letUserSelectRow = NO;
self.tableView.scrollEnabled = NO;

//Add the done button.
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] 
                                           initWithBarButtonSystemItem:UIBarButtonSystemItemDone 
                                           target:self action:@selector(doneSearching_Clicked:)] autorelease];
}

- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText {

//Remove all objects first.
[copyListOfItems removeAllObjects];

if([searchText length] > 0) {

    [ovController.view removeFromSuperview];
    searching = YES;
    letUserSelectRow = YES;
    self.tableView.scrollEnabled = YES;
    [self searchTableView];
}
else {

    [self.tableView insertSubview:ovController.view aboveSubview:self.parentViewController.view];

    searching = NO;
    letUserSelectRow = NO;
    self.tableView.scrollEnabled = NO;
}

[self.tableView reloadData];
}

- (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar {

[self searchTableView];
}

- (void) searchTableView {

NSString *searchText = searchBar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];

for (NSDictionary *dictionary in listOfItems)
{
    NSArray *array = [dictionary objectForKey:@"Elements"];
    [searchArray addObjectsFromArray:array];
}

for (NSString *sTemp in searchArray)
{
    NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];

    if (titleResultsRange.length > 0)
        [copyListOfItems addObject:sTemp];
}

[searchArray release];
searchArray = nil;
}

- (void) doneSearching_Clicked:(id)sender {

searchBar.text = @"";
[searchBar resignFirstResponder];

letUserSelectRow = YES;
searching = NO;
self.navigationItem.rightBarButtonItem = nil;
self.tableView.scrollEnabled = YES;

[ovController.view removeFromSuperview];
[ovController release];
ovController = nil;

[self.tableView reloadData];
}

// 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
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}   
else if (editingStyle == UITableViewCellEditingStyleInsert) {
    // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}   

} */

#pragma mark -
#pragma mark Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selectedCountry = nil;

if(searching)
    selectedCountry = [copyListOfItems objectAtIndex:indexPath.row];
else {

    NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
    NSArray *array = [dictionary objectForKey:@"Countries"];
    selectedCountry = [array objectAtIndex:indexPath.row];
}

//Initialize the detail view controller and display it.
if ([[listOfItems  objectAtIndex:indexPath.row] isEqual:@"neon"]){
Neon *abo = [[Neon alloc] initWithNibName:@"Neon" bundle:nil];
//dvController.selectedCountry = selectedCountry;
[self.navigationController pushViewController:abo animated:YES];
[abo release];
}

}


#pragma mark -
#pragma mark Memory management

- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Relinquish ownership any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}


- (void)dealloc {
[back release];
[tableView release];
[super dealloc];
}


@end
3

3 Answers

0
votes

Not knowing much about your code, I can't tell you the exact problem, however:

At the top, you differentiate between two different arrays depending on the value of searching. Later, you only use the array you'd use when searching is false, with the same index, which seems to be an array of NSDictionarys, not NSStrings. You also seem to be accessing it using indexPath.section the first time, and indexPath.row the second time.

The line I'm talking about, in particular, is this one:

if ([[listOfItems  objectAtIndex:indexPath.row] isEqual:@"neon"]){

Based on the previous code, that is, this line:

NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];

I'm guessing that listOfItems contains a number of items equal to the number of sections in your table view, not the number of rows in the section you clicked in, and I'm also guessing that the return value will never be equal to @"neon" because it is an NSDictionary.

0
votes

According to the exception you are getting you are calling objectAtIndex: with a value of 60 and the NSMutableArray doesn't have anything in it (range 0..0). You need to fix this before you'll get to the push code.

You should be able to tell from the call stack in the debugger which array is being accessed when the exception occurs or you can add NSLog before you do objectAtIndex: to see what you have. For example, you have:

if ([[listOfItems  objectAtIndex:indexPath.row] isEqual:@"neon"]){

If you add this next line before the one above, you would be able to see what index you are trying to access (indexPath.row) and how many you actually have in listOfItems:

NSLog(@"listOfItems has %d, accessing %d", [listOfItems count], indexPath.row);
0
votes

Solved with this code for anyone wondering. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *selectedCountry = nil;

if(searching)
    selectedCountry = [copyListOfItems objectAtIndex:indexPath.row];
else {

    NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
    NSArray *array = [dictionary objectForKey:@"Elements"];
    selectedCountry = [array objectAtIndex:indexPath.row];
}

//Initialize the detail view controller and display it.
NSLog(@"listOfItems has %d, accessing %d", [listOfItems count], indexPath.row);
NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:@"Elements"];
NSString *cellValue = [array objectAtIndex:indexPath.row];

if ([cellValue isEqual:@"neon"]){
    NSLog(@"Neon");
    Neon *abo = [[Neon alloc] initWithNibName:@"Neon" bundle:nil];
    [self.navigationController pushViewController:abo animated:YES];
    NSLog(@"Neon Worked");
    [abo release];
}

}