Question

I am quite new with Objective C and I have been having trouble a a little while and I have been looking over answers, watching tutorials, and I have not been able to find a solution to my problem. Maybe its right in front of my face and I am not seeing it...I think it has something that has to do with the NSRange of my UISearch Bar. But I am not 100% sure.

I am trying to search through array that has the keys of my dictionary of countries, I have set up several NSLogs and I see that the keys are going into the array I have setup to save them in and then i get the error below...

So to my understanding of this, it is counting countryKeys which has 5, so index 4 should exist, should it not? but then it shows 0 .. 3, So I this is why I am thinking i am using NSRange incorrectly. I have watched some UISearchBar and For loop tutorials so far and i am understanding For loops and them better i guess I need to figure out NSRange then.

Let me know if you don't understand my thought process or anything that I mentioned..

    Filtered Countries (
        ATE,
        ARE,
        USA,
        JAP,
        CAN
    )
    *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 4 beyond bounds [0 .. 3]'

-

#import "ViewController.h"
@interface ViewController ()
@end

@implementation ViewController

@synthesize dictTableView, mySearchBar, countriesInRegion, filteredCountries, isFiltered, regionCodes, countryKey, countryKeys, countryInfo, sortedKeysArray, regionCode, dict1;

- (void)viewDidLoad
{
    [super viewDidLoad];

    dict1 = [[NSMutableDictionary alloc] init];
    NSMutableDictionary *subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:@"United States",@"US",@"USA", @"NAC", nil]
                                                                        forKeys: [NSArray arrayWithObjects:@"countryName", @"countryAbbrev", @"countryID", @"countryRegion", nil]];
    [dict1 setObject:subDict forKey:@"USA"];

    subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:@"Canada", @"CA", @"CAN", @"NAC", nil]
                                                   forKeys: [NSArray arrayWithObjects:@"countryName", @"countryAbbrev", @"countryID", @"countryRegion", nil]];
    [dict1 setObject:subDict  forKey:@"CAN"];

    subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:@"Japan", @"JP", @"JAP", @"EAS", nil]
                                                   forKeys: [NSArray arrayWithObjects:@"countryName", @"countryAbbrev", @"countryID", @"countryRegion", nil]];
    [dict1 setObject:subDict forKey:@"JAP"];

    subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:@"United Arab Emirates", @"AE", @"ARE", @"MEA", nil]
                                                   forKeys: [NSArray arrayWithObjects:@"countryName", @"countryAbbrev", @"countryID", @"countryRegion", nil]];
    [dict1 setObject:subDict forKey:@"ARE"];

    subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:@"Antigua and Barbuda", @"AG", @"ATE", @"LCN", nil]
                                                   forKeys: [NSArray arrayWithObjects:@"countryName", @"countryAbbrev", @"countryID", @"countryRegion", nil]];
    [dict1 setObject:subDict forKey:@"ATE"];

    regionCodes = [[NSMutableDictionary alloc] init];

    countryKeys = [dict1 allKeys];
    NSLog(@"countryKeys %@", countryKeys);

    sortedKeysArray = [countryKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];

    for (int i = 0; i < [sortedKeysArray count]; i++) {
        countryKey = [sortedKeysArray objectAtIndex:i];
        countryInfo = [dict1 objectForKey:countryKey]; // NSLog(@"returning countryKey to countryInfo %@", countryInfo);
        regionCode = [countryInfo objectForKey:@"countryRegion"]; // NSLog(@" adding countryRegion Key to regionCode %@", regionCode);
        //  NSLog(@"the contents of countryInfo is %@", countryInfo);

        if (![regionCodes objectForKey:regionCode]) {
            countriesInRegion = [[NSMutableArray alloc] init];
            [regionCodes setObject:countriesInRegion forKey:regionCode];

            [countriesInRegion addObject:countryInfo]; // NSLog(@"if adding countryInfo to initialCountries %@", countryInfo);

        }
        else{
            countriesInRegion = [regionCodes objectForKey:regionCode];
            [countriesInRegion addObject:countryInfo]; // NSLog(@"else adding countryInfo to initialCountries %@", countryInfo);
        }
    }

}



- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    if (isFiltered == NO)
    {
        return countryInfo.count;
    }
    else
    {
        return filteredCountries.count;
    }

}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

{
    NSArray *sortKey = [regionCodes allKeys];
    sortedKeysArray = [sortKey sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
    return [sortedKeysArray objectAtIndex:section];

}


- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
    NSString *regionKey = [[regionCodes allKeys] objectAtIndex:section];
    countriesInRegion = [regionCodes objectForKey:regionKey];

    if (isFiltered == NO)
    {
        return countriesInRegion.count;
    }
    else
    {
        return filteredCountries.count;
    }
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    UITableViewCell *cell = nil;

    cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:@"Cell"];

        UILabel *countryNameLabel = [[UILabel alloc] initWithFrame:(CGRectMake(10, 0, 220, 44))];
        [countryNameLabel setBackgroundColor:[UIColor clearColor]];

        UILabel *countryAbbrevLabel = [[UILabel alloc] initWithFrame:(CGRectMake(230, 0, 75, 44))];
        [countryNameLabel setBackgroundColor:[UIColor clearColor]];

        UILabel *countryIDLabel = [[UILabel alloc] initWithFrame:(CGRectMake(275, 0, 50, 44))];
        [countryNameLabel setBackgroundColor:[UIColor clearColor]];

        [cell.contentView addSubview:countryNameLabel];
        [cell.contentView addSubview:countryAbbrevLabel];
        [cell.contentView addSubview:countryIDLabel];
    }
    NSArray *regionKeys = [regionCodes allKeys];
    NSString *regionKey = [regionKeys objectAtIndex:indexPath.section];
    countriesInRegion = [regionCodes objectForKey:regionKey];
    NSLog(@"Countries in Region %@", countriesInRegion);
    countryInfo = [countriesInRegion objectAtIndex:indexPath.row];

    NSArray *subviews = [cell.contentView subviews];
    UILabel *nameLabel = [subviews objectAtIndex:0];
    UILabel *abbrevLabel = [subviews objectAtIndex:1];
    UILabel *idLabel = [subviews objectAtIndex:2];
//    NSLog(@"6 - Countries in Region %@", countriesInRegion);

    if (isFiltered == NO)
    {
        nameLabel.text = [countryInfo objectForKey:@"countryName"];
        abbrevLabel.text = [countryInfo objectForKey:@"countryAbbrev"];
        idLabel.text = [countryInfo objectForKey:@"countryID"];
//        NSLog(@"5 - Our list of countries: %@", nameLabel.text);
//        NSLog(@"Country Info %@",countryInfo);

    }
    else
    {
        nameLabel.text = [filteredCountries objectAtIndex:2];
        abbrevLabel.text = [filteredCountries objectAtIndex:1];
        idLabel.text = [filteredCountries objectAtIndex:0];

        NSLog(@"4 - Here are your results: %@", filteredCountries);

    }
    return cell;
}

#pragma mark - UISearchBarDelegate Methods

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

    if (searchText.length == 0) {
        isFiltered = NO;

    }
    else
    {
        isFiltered = YES;
        NSLog(@"You entered %@", searchText);
        filteredCountries = [[NSMutableArray alloc] init];
        countryKeys = [dict1 allKeys];
        NSLog(@"countryKeys %@", countryKeys);

        for (int i = 0; i < countryKeys.count; i++) {
            countryKey = [countryKeys objectAtIndex:i];
            NSLog(@"country key is %@", countryKey);
            {
                NSRange countryNameRange = [countryKey rangeOfString:searchText options:NSCaseInsensitiveSearch];


                if (countryNameRange.location !=NSNotFound)
                {
                    [filteredCountries addObject:countryKey];

                    NSLog(@"Filtered Countries %@", filteredCountries);
                }
            }
        }

    }
    [dictTableView reloadData];
}





- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    [mySearchBar resignFirstResponder];

}




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


@end
Was it helpful?

Solution

That error simply means that you are exceeding the bound of an array.

Specifically at a first sight, I think you got wrong the number of sections and that it doesn't match the number of elements in your array.

I noticed that when filtered is equal to YES you are returning filteredCountries.count for both number of rows and number of sections.

It doesn't look right and I think you should double check you indexes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top