1

I am still new to objective C. I would like to create a 2D array of unknown size such that i can access it and add values. I come from a C++ background and looking at tutorial point and examples such as Declaring and Initializing 2D array of unknown size in C it seems there is a similarity in creation of a 2D array between C++ and Objective C.

I have implemented the following example and i get an error:

Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'**

I am not sure what is causing the error, i would be grateful for assistance in solving this error and understanding it.

-(NSMutableArray *)categoryCk
{
    if (!_categoryCk)
    {
        _categoryCk = [[NSMutableArray alloc] init];
    }
    return _categoryCk;
}
-(NSMutableArray *)subcategoryCv
{
    if (!_subcategoryCv)
    {
        _subcategoryCv = [[NSMutableArray alloc] init];
    }
    return _subcategoryCv;
}

-(NSMutableArray *)subcategoryCk
{
    if (!_subcategoryCk)
    {
         _subcategoryCk = [[NSMutableArray alloc] init];
    }
    return _subcategoryCk;
}
-(NSMutableArray *)outcomeCv
{
    if (!_outcomeCv)
    {
        _outcomeCv = [[NSMutableArray alloc] init];
    }
    return _outcomeCv;
}

-(NSMutableArray *)outcomeCk
{
    if (!_outcomeCk)
    {
        _outcomeCk = [[NSMutableArray alloc] init];
    }
    return _outcomeCk;
}

Then the loops to create the arrays:

if([categories count]>0){

    for (int i =0; i < categories.count; i++)

    {
        NSArray* subCategories= [categories[i] objectForKey: @"subCategories"];


        NSDictionary *categoryItems = [categories objectAtIndex:i];
        NSString *category = [categoryItems objectForKey:@"cv"];
        NSLog(@"%@",category);
        [self.categoryCv addObject:category];
        NSString *categoryNum = [categoryItems objectForKey:@"ck"];
        [self.categoryCk addObject:categoryNum];

        if ([subCategories count] > 0){

        for (int j = 0; j < subCategories.count; j++) {

            if (self.subcategoryCv.count <= i) {
                [self.subcategoryCv addObject:[[NSMutableArray alloc] init]];
            }

            if ([self.subcategoryCv[i] count] <= j) {
                [self.subcategoryCv[i] addObject:[[NSMutableArray alloc] init]];
            }
            if (self.subcategoryCk.count <= i) {
                [self.subcategoryCk addObject:[[NSMutableArray alloc] init]];
            }

            if ([self.subcategoryCk[i] count] <= j) {
                [self.subcategoryCk[i] addObject:[[NSMutableArray alloc] init]];
            }

            NSDictionary *subcategoryItems = [subCategories objectAtIndex:j];
            NSString *subCategoryCv = [subcategoryItems objectForKey:@"cv"];
            [self.subcategoryCv[i][j] addObject:subCategoryCv];
            NSString *subCatNum = [subcategoryItems objectForKey:@"ck"];
            [self.subcategoryCk[i][j] addObject:subCatNum];

            NSArray* outcome =[[subCategories objectAtIndex:j] objectForKey:@"outcomes"];

            if ([outcome count] > 0) {

            for (int k = 0; k < outcome.count; k++) {

                if (self.outcomeCv.count <= j) {
                    [self.outcomeCv addObject:[[NSMutableArray alloc] init]];
                }

                if ([self.outcomeCv[j] count] <= k) {
                    [self.outcomeCv[j] addObject:[[NSMutableArray alloc] init]];
                }


                if (self.outcomeCk.count <= j) {
                    [self.outcomeCk addObject:[[NSMutableArray alloc] init]];
                }

                if ([self.outcomeCk[j] count] <= k) {
                    [self.outcomeCk[j] addObject:[[NSMutableArray alloc] init]];
                }

                NSDictionary *outComeItems = [outcome objectAtIndex:k];
                NSString *outcomeCategoryCV = [outComeItems objectForKey:@"cv"];
                //NSLog(@"%@",outcomeCatCV);
                [self.outcomeCv[j][k] addObject:outcomeCategoryCV];
                NSString *outCatNum = [outComeItems objectForKey:@"ck"];
                [self.outcomeCk[j][k] addObject:outCatNum];

            }
            }else{

            UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Alert"
                                                                               message:@"Error loading data from service : Empty Outcomes data"
                                                                        preferredStyle:UIAlertControllerStyleAlert];

            UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                                      handler:^(UIAlertAction * action) {}];

            [alert addAction:defaultAction];
            [self presentViewController:alert animated:YES completion:nil];

            }
        }
        } else{

            UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Alert"
                                                                           message:@"Error loading data from service : Empty Sub-Categories data"
                                                                    preferredStyle:UIAlertControllerStyleAlert];

            UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                                  handler:^(UIAlertAction * action) {}];

            [alert addAction:defaultAction];
            [self presentViewController:alert animated:YES completion:nil];
        }
    }

}else{

    UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Alert"
                                                                   message:@"Error loading data from service : Empty Categories data"
                                                            preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {}];

    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];

}

This is how i try to access the array :

 cell.textLabel.text = [self.outcomeCv[categoryIndex][subcategoryIndex] objectAtIndex:indexPath.row] ;
trungduc
  • 11,926
  • 4
  • 31
  • 55
kaddie
  • 233
  • 1
  • 5
  • 27
  • 1
    i think you are using 5 1D arrays instead of 2D currently. Right? named categoryCk, subcategoryCk, subcategoryCv, outcomeCk, outcomeCv right? – Syed Qamar Abbas Nov 16 '17 at 08:08
  • yes u are right but im trying to create 2D arrays out of these arrays. Such that i can be able to get categoryCk[i][j], subcategoryCk[i][j], subcategoryCv[i][j], outcomeCk[i][j], outcomeCv[i][j] – kaddie Nov 16 '17 at 08:27

1 Answers1

1

When you call subcategoryCv[i][j], you have to make sure that

subcategoryCv.count > i && subcategoryCv[i].count > j

if not, you will got crash in you question.

To prevent it, you need to add a new NSMutableArray to subcategoryCv when subcategoryCv.count <= i and add a new NSMutableArray to subcategoryCv[i] when subcategoryCv[i].count <= j.

It's same with another 2D array. For example with subcategoryCv

if (self.subcategoryCv.count <= i) {
  [self.subcategoryCv addObject:[[NSMutableArray alloc] init]];
}

if ([self.subcategoryCv[i] count] <= j) {
  [self.subcategoryCv[i] addObject:[[NSMutableArray alloc] init]];
}

NSDictionary *subcategoryItems = [subCategories objectAtIndex:j];
NSString *subCategoryCv = [subcategoryItems objectForKey:@"cv"];
[self.subcategoryCv[i][j] addObject:subCategoryCv];
NSString *subCatNum = [subcategoryItems objectForKey:@"ck"];
[self.subcategoryCk[i][j] addObject:subCatNum];
trungduc
  • 11,926
  • 4
  • 31
  • 55
  • Sorry i am lost a bit, do you mean i should put a validation to check if the count of the array categoryCv.count, subCategoryCv.count and outcomeCv.count is less than the count variables. Im not sure i understand why i should do this. – kaddie Nov 16 '17 at 09:36
  • For example, if `categoryCk` array has 3 elements but you call `categoryCk[3]`. App will throw an exception like in your question. You only can call `categoryCk[3]` if `categoryCk` array has more or equal 4 elements. – trungduc Nov 16 '17 at 09:39
  • maybe the reason why i fail to understand is because of a few typos in your answer let me edit them. and this line [self.subcategoryCv[i] addObject:[NSMutableArray alloc] init]]; throws an error saying Expected : – kaddie Nov 16 '17 at 09:46
  • @kudzaimhou my code is used to resolve problem with `subcategoryCv`. You need to apply it with the others to make them work fine. – trungduc Nov 16 '17 at 09:51
  • On another hand can you please edit the answer because im afraid i might change it to something it wasnt intended to be. First part im calling subcategoryCk[i][j] not categoryCk[i][j] then another part is where exactly in my code is the suggestion of creating a [self.subcategoryCv[i] addObject:[[NSMutableArray alloc] init]]; going. – kaddie Nov 16 '17 at 09:54
  • Ok this part : When you call categoryCk[i][j], has to change to subcategoryCk[i][j] – kaddie Nov 16 '17 at 10:04
  • and i am failing to make a link to this part : categoryCk.count > i && categoryCk[i].count > j do u mean categoryCk.count > i && scategoryCk[i].count > j – kaddie Nov 16 '17 at 10:06
  • I mean number elements of `categoryCk` have to be bigger than `i`. And number elements of element which has index `i` inside `categoryCk ` have to be bigger than `j`. Let read carefully. `categoryCk` and `categoryCk[i]` – trungduc Nov 16 '17 at 10:09
  • i have added your suggestion and still it doesn't work, please check updated code on the question for the part where i added your code. – kaddie Nov 16 '17 at 10:50
  • @kudzaimhou do you know what line throws this error? – trungduc Nov 16 '17 at 11:08
  • thats what i am busy debuging, my thought is that this may be caused by the fact that i am trying to creat jagged arrays but i could be wrong. – kaddie Nov 16 '17 at 11:15
  • @kudzaimhou i found that you didn't check validate for `outcomeCk` and `subcategoryCk`, that's why you still got crash – trungduc Nov 16 '17 at 11:46
  • i added the outcomeCk and subCategoryCk and now i get Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]' – kaddie Nov 16 '17 at 12:52
  • @kudzaimhou one more, `self.outcomeCv.count <= i` is wrong. It must be `self.outcomeCv.count <= j`. Please check all of your validation – trungduc Nov 16 '17 at 12:59
  • i updated the code and and now its Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 12 beyond bounds [0 .. 11]' – kaddie Nov 16 '17 at 13:07
  • @kudzaimhou replace `if (self.subcategoryCv.count <= j)` with `if (self.subcategoryCv.count <= i)` pls – trungduc Nov 16 '17 at 13:15
  • Yes it works now.@trungduc I am very grateful for your time and effort in helping me debug this error. They are very few who have such compassionate, thank you very very much. i am at a lose of words. – kaddie Nov 16 '17 at 13:23
  • Thank god, you get out of this error -.-. Good luck and happy coding my friend ;) – trungduc Nov 16 '17 at 13:30