1

In one class called LevelSelectViewController, I have this public property

    @property (nonatomic, strong, getter=getLevelNumber) NSNumber *levelNumber;

which stores an int value based on a UIButton* touch selection using the method

     - (IBAction)buttonPressedSoWhatNumber:(id)sender
     {
         UIButton *button = (UIButton *)sender;
         int row = button.tag;
         _levelNumber = [NSNumber numberWithInt:row];
     }

When I put a breakpoint at the end of the method to see if my touch interaction triggers the correct result based on what I coded (when I press button 1, really), _levelNumber reads 0 (which it should). I also have a getter method written out for it.

Now, in this second class called GameViewController, I have a method setUpBoards which (should) obtain that value for *levelNumber. It looks like this:

    - (void)setUpBoards {
        LevelSelectViewController* level = [[LevelSelectViewController alloc] init];
        [level getLevelNumber];
        [self createLevelModel:(int)level];
    }

In that same class, the method createLevelModel:(int)levelIndex uses that value to be passed to 5 initialization methods that access a Levels.plist file to load data for my game.

Basically, that number represents what level button I pressed and uses that number to load the correct level. In another manner, I have verified that those 5 initialization methods work along with loading data from my Levels.plist file.

Now, between the transition from LevelSelectViewController to GameViewController, I receive the NSRangeException error message:

   'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (554166800) beyond bounds (1)'

even when pressing the 1 button (which should work considering I only have Item 0 in my plist typed out.......which, again, I verified worked using another manner).

TO ADD ON TO THIS. Here's another important method:

    -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
             cellForItemAtIndexPath:(NSIndexPath *)indexPath {

        static NSString *cellIdentifier = @"cvCell";
        CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
        NSMutableArray *data = [self.dataArray objectAtIndex:indexPath.section];
        NSString *cellData = [data objectAtIndex:indexPath.row];
        [cell.buttonClick setTag:indexPath.row];
        [cell.buttonClick addTarget:self action:@selector(buttonPressedSoWhatNumber:)
           forControlEvents:UIControlEventTouchUpInside];
        [cell addSubview:cell.buttonClick];
        return cell;
    }

Any insight?

Here's the push controller method from LevelSelectViewController to GameViewController:

    -(IBAction)buttonPressed:(id)sender {
         GameViewController* obj = [[GameViewController alloc] initWithNibName:@"GameViewController" bundle:nil];
         [self.navigationController pushViewController:obj animated:YES];
    }

buttonPressed: is another method given to the UIButton*

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Frank
  • 107
  • 9
  • I get suspicious when I see a straight alloc/init of a UIViewController into a local variable and the view controller isn't presented; This means that the view controller will be deallocated as soon as the method exits. Which line of code is throwing the exception? It seems that the array index has come from a number that wasn't initialised, which isn't surprising since you don't set `levelNumber` anywhere when you create the view controller – Paulw11 May 19 '16 at 01:42
  • Yea you're right, so the value getting passed into those 5 initializers is 525827056 when it should be 1 (the plist is out of range). Which means that setUpBoards method is not delivering with the integer value. When I set breakpoints throughout the setUpBoards method I can't seem to capture any values because the exception is thrown somewhere in the middle of all that. The levelNumber is set in another file, LevelSelectViewController, and I get it in GameViewController. Unless I'm incorrectly getting that property. – Frank May 19 '16 at 01:52
  • I think you need to get a reference to the actual level select view controller that you have on screen rather than just creating a new one – Paulw11 May 19 '16 at 01:54
  • How would I do that? Sorry... – Frank May 19 '16 at 01:54
  • You need to get the value from the button in `buttonPressedSoWhatNumber` and pass this value to your new ` GameViewController`, probably through `prepareForSegue` or however you are presenting the new view controller – Paulw11 May 19 '16 at 01:58
  • I'm using [self.navigationController pushViewController:viewController animated:YES]; I've been trying to figure out how to pass that value in to that method but I never could. Any ideas? – Frank May 19 '16 at 02:03
  • Can you edit your question to show that code; the method where you push the new view controller? – Paulw11 May 19 '16 at 02:06
  • Hopefully that helps – Frank May 19 '16 at 02:25

2 Answers2

0

The problem is that you are casting a pointer to an int.

@property (nonatomic, strong, getter=getLevelNumber) NSNumber *levelNumber;

Defines a pointer to an object of type NSNumber.

[self createLevelModel:(int)level];

Is casting that NSNumber * to an int.

You also have another bug in that you are setting level as the view controller and calling getLevelNumber but not actually using the returned value. So here is what I would do. Firstly you don't need to define an NSNumber and don't need a custom getter. Just use this:

@property (nonatomic, assign) int levelNumber;

Then this becomes much simple:

- (void)setUpBoards {
    LevelSelectViewController* levelSelectViewController = [[LevelSelectViewController alloc] init];
    [self createLevelModel: levelSelectViewController.levelNumber]; // Always going to be zero at this point.
}
drekka
  • 20,957
  • 14
  • 79
  • 135
  • While this is correct, it is missing the fundamental problem that simply instantiating a new `LevelSelectViewController` won't give a meaningful value – Paulw11 May 19 '16 at 01:59
  • Saw that in your previous comment. But wanted to concentrate on the two main bugs. – drekka May 19 '16 at 02:03
  • There are also a number of issues with the additional code. For example using old style indexing of arrays, adding a sub view of a cell to itself, and issues with reuse. One thing at a time. – drekka May 19 '16 at 02:05
  • Christ I'm (as you can tell) a good ol beginner. How poorly coded is the cell block? – Frank May 19 '16 at 02:07
  • Np @Frank It's hard to really decide how I would do it because there are a number of things which are not clear. Simplicity and clarity in coding is something well worth spending time on. For example `buttonClick` appears to be a control of some sort, yet it's name suggests something else all together. A simple miss-name like this can lead to much confusion. The next thing I would look at is why you are adding it as a subview. It appears to already be on the cell. This is important because when the cell is reused it will add it again. – drekka May 19 '16 at 02:12
  • I will check out the cell info later. Thanks, and that bit about the subview makes sense. Your suggestion (getting back to the integer problem) actually worked but levelSelectViewController.levelNumber is always 0 for some reason (better than the NSExceptionRange error). Any thoughts? – Frank May 19 '16 at 02:19
  • I have a feeling the non-specific LevelSelectViewController alloc-init is causing the empty integer for the levelNumber property. When I put a breakpoint back in the reformatted buttonPressedSoWhatNumber method, and click (let's say button 3) it correctly stores 2 for that property. – Frank May 19 '16 at 02:21
  • Given that you have only just created the controller on the previous line and not displayed it for the user to select a level with, then it's logical the level is still at zero. I think you need to do some reading around presenting view controllers and understanding the life cycles of them. :-) – drekka May 19 '16 at 02:22
0

You need a simple int property in LevelSelectViewController that you can use to store the level that has been selected:

@property int levelSelected;

The store the selected value in your button press handler:

- (IBAction)buttonPressedSoWhatNumber:(UIButton *)sender
{
     self.levelSelected = sender.tag;
}

Then you can pass this to a corresponding int property on your GameViewController;

-(IBAction)buttonPressed:(id)sender {
     GameViewController* obj = [[GameViewController alloc] initWithNibName:@"GameViewController" bundle:nil];
     obj.level = self.selectedLevel
     [self.navigationController pushViewController:obj animated:YES];
}
Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • BOOM! Awesome , thanks for all the help. This did the trick, and I never even knew you could do that until now...as an experienced novice this was very helpful. – Frank May 19 '16 at 03:46