NSRangeException

0

I'm trying to use two buttons to cycle through an array of images. I'm using a buttonPressed function that identifies the tag of the left or right button, and should change the image that is displayed. Problem is, the function works perfectly when going right (incrementing the array), but if I try to go left (decrement) the program crashes. I've tried changing the values the variables are initialized to and the values used to cycle the arrays, but nothing seems to fix it. Any help is greatly appreciated.

.h

//  FirstViewController.h
//  TabTemplate
//
//  Created by Paul R Woidke on 6/1/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import <UIKit/UIKit.h>
#include <stdlib.h>



@interface FirstViewController : UIViewController {
    UIImageView* hat;
    UIImageView* shirt;
    UIImageView* pants;
    UIImageView* shoes;

    NSArray *hatArray;
    NSArray *shirtArray;
    NSArray *pantsArray;
    NSArray *shoesArray;
}

@property (nonatomic, retain) IBOutlet UIImageView* hat;
@property (nonatomic, retain) IBOutlet UIImageView* shirt;
@property (nonatomic, retain) IBOutlet UIImageView* pants;
@property (nonatomic, retain) IBOutlet UIImageView* shoes;

@property (nonatomic, retain) IBOutlet NSArray* hatArray;
@property (nonatomic, retain) IBOutlet NSArray* shirtArray;
@property (nonatomic, retain) IBOutlet NSArray* pantsArray;
@property (nonatomic, retain) IBOutlet NSArray* shoesArray;

- (IBAction)buttonPressed:(id) sender;
- (IBAction)lockButtonPressed:(id) sender;
- (IBAction)weatherButtonPressed:(id) sender;
- (IBAction)randomizeButtonPressed:(id) sender;

@end

.m

//  FirstViewController.m
//  TabTemplate
//
//  Created by Paul R Woidke on 6/1/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "FirstViewController.h"


@implementation FirstViewController

@synthesize hat;
@synthesize shirt;
@synthesize pants;
@synthesize shoes;

@synthesize hatArray;
@synthesize shirtArray;
@synthesize pantsArray;
@synthesize shoesArray;

NSInteger hatImage;
NSInteger shirtImage;
NSInteger pantsImage;
NSInteger shoesImage;

-(void) displayOutfit {
    UIImage *hatImg = [hatArray objectAtIndex:hatImage];
    [hat setImage:hatImg]; 
    UIImage *shirtImg = [shirtArray objectAtIndex:shirtImage];
    [shirt setImage:shirtImg]; 
    UIImage *pantsImg = [pantsArray objectAtIndex:pantsImage];
    [pants setImage:pantsImg]; 
    UIImage *shoesImg = [shoesArray objectAtIndex:shoesImage];
    [shoes setImage:shoesImg];  
}

- (IBAction)buttonPressed:(id) sender {

    NSInteger senderLabel = [sender tag];

    switch (senderLabel) {

//Going right
        case 2:

            NSLog(@"Hat number: %d", hatImage);
            NSLog(@"Hat Array count: %d", [hatArray count]);

            if (hatImage == [hatArray count])
                hatImage = 0;
            UIImage *hatImg2 = [hatArray objectAtIndex:hatImage];
            [hat setImage:hatImg2]; 
            hatImage++;
            break;

        case 4:
            if (shirtImage == [shirtArray count])
                shirtImage = 0;
            UIImage *shirtImg2 = [shirtArray objectAtIndex:shirtImage];
            [shirt setImage:shirtImg2]; 
            shirtImage++;
            break;

        case 6:
            if (pantsImage == [pantsArray count])
                pantsImage = 0;
            UIImage *pantsImg = [pantsArray objectAtIndex:pantsImage];
            [pants setImage:pantsImg]; 
            pantsImage++;
            break;

        case 8: 
            if (shoesImage == [shoesArray count])
                shoesImage = 0;
            UIImage *shoesImg2 = [shoesArray objectAtIndex:shoesImage];
            [shoes setImage:shoesImg2]; 
            shoesImage++;
            break;

//Going left
        case 1:
            if (hatImage == 0)
                hatImage = 3;
            UIImage *hatImg = [hatArray objectAtIndex:hatImage];
            [hat setImage:hatImg]; 
            hatImage--;
            break;

        case 3:
            if ((shirtImage) == 0)
                shirtImage = [shirtArray count];
            UIImage *shirtImg = [shirtArray objectAtIndex:shirtImage];
            [shirt setImage:shirtImg]; 
            shirtImage--;
            break;

        case 5:
            if ((pantsImage) == 0)
                pantsImage = [pantsArray count];
            UIImage *pantsImg2 = [pantsArray objectAtIndex:pantsImage];
            [pants setImage:pantsImg2]; 
            pantsImage--;
            break;

        case 7: 
            if ((shoesImage) == 0)
                shoesImage = [shoesArray count];
            UIImage *shoesImg = [shoesArray objectAtIndex:shoesImage];
            [shoes setImage:shoesImg]; 
            shoesImage--;
            break;

    }
}

- (IBAction)lockButtonPressed:(id) sender {
    NSLog(@"Lock Button Pressed");
}

- (IBAction)weatherButtonPressed:(id) sender {
    NSLog(@"Weather Button Pressed");
}

- (IBAction)randomizeButtonPressed:(id) sender {
    NSLog(@"Randomize Button Pressed");


    int randHat = rand() % [hatArray count];
    int randShirt = rand() % [shirtArray count];
    int randPants = rand() % [pantsArray count];
    int randShoes = rand() % [shoesArray count];
    NSLog(@"hat %d\nshirt %d\npants %d\nshoes %d", randHat, randShirt, randPants, randShoes);

    hatImage = randHat;
    shirtImage = randShirt;
    pantsImage = randPants;
    shoesImage = randShoes;

    [self displayOutfit];
}


/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {

    //Generate image arrays
    hatArray = [[NSArray arrayWithObjects: 
                    [UIImage imageNamed:@"h1.png"], 
                    [UIImage imageNamed:@"h2.png"], 
                    [UIImage imageNamed:@"h3.png"], 
                    nil] retain];

    shirtArray = [[NSArray arrayWithObjects: 
                   [UIImage imageNamed:@"s1.png"], 
                   [UIImage imageNamed:@"s2.png"],
                   [UIImage imageNamed:@"s3.png"], 
                   [UIImage imageNamed:@"s4.png"],
                   [UIImage imageNamed:@"s5.png"], 
                   [UIImage imageNamed:@"s6.png"],
                   nil] retain];

    pantsArray = [[NSArray arrayWithObjects: 
                   [UIImage imageNamed:@"p1.png"], 
                   [UIImage imageNamed:@"p2.png"],
                   [UIImage imageNamed:@"p3.png"],
                   [UIImage imageNamed:@"p4.png"],
                   nil] retain];

    shoesArray = [[NSArray arrayWithObjects: 
                   [UIImage imageNamed:@"ss1.png"], 
                   [UIImage imageNamed:@"ss2.png"],
                   [UIImage imageNamed:@"ss3.png"],
                   nil] retain];

    hatImage = 0;
    shirtImage = 0;
    pantsImage = 0;
    shoesImage = 0;

    UIImage *hatImg = [hatArray objectAtIndex:hatImage];
    [hat setImage:hatImg]; 
    UIImage *shirtImg = [shirtArray objectAtIndex:shirtImage];
    [shirt setImage:shirtImg]; 
    UIImage *pantsImg = [pantsArray objectAtIndex:pantsImage];
    [pants setImage:pantsImg]; 
    UIImage *shoesImg = [shoesArray objectAtIndex:shoesImage];
    [shoes setImage:shoesImg]; 

    [super viewDidLoad];
}


/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

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

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

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.hat = nil;
    self.shirt = nil;
    self.pants = nil;
    self.shoes = nil;
    self.hatArray = nil;
    self.shirtArray = nil;
    self.pantsArray = nil;
    self.shoesArray = nil;
}


- (void)dealloc {
    [hat release];
    [shirt release];
    [pants release];
    [shoes release];
    [hatArray release];
    [shirtArray release];
    [pantsArray release];
    [shoesArray release];
    [super dealloc];
}

@end

Console output (displays array count and value of current image):

[Session started at 2011-06-16 16:30:50 -0400.]
2011-06-16 16:31:03.192 TabTemplate[2478:207] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSArray objectAtIndex:]: index 3 beyond bounds [0 .. 2]'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x00db3be9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x00f085c2 objc_exception_throw + 47
    2   CoreFoundation                      0x00da980c -[__NSArrayI objectAtIndex:] + 236
    3   TabTemplate                         0x000026c8 -[FirstViewController buttonPressed:] + 569
    4   UIKit                               0x002bca6e -[UIApplication sendAction:to:from:forEvent:] + 119
    5   UIKit                               0x0034b1b5 -[UIControl sendAction:to:forEvent:] + 67
    6   UIKit                               0x0034d647 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 527
    7   UIKit                               0x0034c1f4 -[UIControl touchesEnded:withEvent:] + 458
    8   UIKit                               0x002e10d1 -[UIWindow _sendTouchesForEvent:] + 567
    9   UIKit                               0x002c237a -[UIApplication sendEvent:] + 447
    10  UIKit                               0x002c7732 _UIApplicationHandleEvent + 7576
    11  GraphicsServices                    0x016e9a36 PurpleEventCallback + 1550
    12  CoreFoundation                      0x00d95064 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
    13  CoreFoundation                      0x00cf56f7 __CFRunLoopDoSource1 + 215
    14  CoreFoundation                      0x00cf2983 __CFRunLoopRun + 979
    15  CoreFoundation                      0x00cf2240 CFRunLoopRunSpecific + 208
    16  CoreFoundation                      0x00cf2161 CFRunLoopRunInMode + 97
    17  GraphicsServices                    0x016e8268 GSEventRunModal + 217
    18  GraphicsServices                    0x016e832d GSEventRun + 115
    19  UIKit                               0x002cb42e UIApplicationMain + 1160
    20  TabTemplate                         0x00002012 main + 84
    21  TabTemplate                         0x00001f92 start + 54
)
terminate called after throwing an instance of 'NSException'

[Session started at 2011-06-16 16:31:13 -0400.]
2011-06-16 16:31:15.966 TabTemplate[2481:207] Hat number: 0
2011-06-16 16:31:15.968 TabTemplate[2481:207] Hat Array count: 3
2011-06-16 16:31:16.390 TabTemplate[2481:207] Hat number: 1
2011-06-16 16:31:16.391 TabTemplate[2481:207] Hat Array count: 3
2011-06-16 16:31:16.790 TabTemplate[2481:207] Hat number: 2
2011-06-16 16:31:16.791 TabTemplate[2481:207] Hat Array count: 3
2011-06-16 16:31:17.446 TabTemplate[2481:207] Hat number: 3
2011-06-16 16:31:17.447 TabTemplate[2481:207] Hat Array count: 3
2011-06-16 16:31:17.902 TabTemplate[2481:207] Hat number: 1
2011-06-16 16:31:17.903 TabTemplate[2481:207] Hat Array count: 3
2011-06-16 16:31:18.199 TabTemplate[2481:207] Hat number: 2
2011-06-16 16:31:18.199 TabTemplate[2481:207] Hat Array count: 3
2011-06-16 16:31:18.526 TabTemplate[2481:207] Hat number: 3
2011-06-16 16:31:18.527 TabTemplate[2481:207] Hat Array count: 3
2011-06-16 16:31:20.503 TabTemplate[2481:207] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSArray objectAtIndex:]: index 3 beyond bounds [0 .. 2]'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x00db3be9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x00f085c2 objc_exception_throw + 47
    2   CoreFoundation                      0x00da980c -[__NSArrayI objectAtIndex:] + 236
    3   TabTemplate                         0x000026c8 -[FirstViewController buttonPressed:] + 569
    4   UIKit                               0x002bca6e -[UIApplication sendAction:to:from:forEvent:] + 119
    5   UIKit                               0x0034b1b5 -[UIControl sendAction:to:forEvent:] + 67
    6   UIKit                               0x0034d647 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 527
    7   UIKit                               0x0034c1f4 -[UIControl touchesEnded:withEvent:] + 458
    8   UIKit                               0x002e10d1 -[UIWindow _sendTouchesForEvent:] + 567
    9   UIKit                               0x002c237a -[UIApplication sendEvent:] + 447
    10  UIKit                               0x002c7732 _UIApplicationHandleEvent + 7576
    11  GraphicsServices                    0x016e9a36 PurpleEventCallback + 1550
    12  CoreFoundation                      0x00d95064 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
    13  CoreFoundation                      0x00cf56f7 __CFRunLoopDoSource1 + 215
    14  CoreFoundation                      0x00cf2983 __CFRunLoopRun + 979
    15  CoreFoundation                      0x00cf2240 CFRunLoopRunSpecific + 208
    16  CoreFoundation                      0x00cf2161 CFRunLoopRunInMode + 97
    17  GraphicsServices                    0x016e8268 GSEventRunModal + 217
    18  GraphicsServices                    0x016e832d GSEventRun + 115
    19  UIKit                               0x002cb42e UIApplicationMain + 1160
    20  TabTemplate                         0x00002012 main + 84
    21  TabTemplate                         0x00001f92 start + 54
)
terminate called after throwing an instance of 'NSException'
iphone
objective-c
xcode
nsarray
asked on Stack Overflow Jun 16, 2011 by Paul Woidke • edited Jun 16, 2011 by Abizern

2 Answers

2

In your "going left" cases you're setting the array index out of bounds. For example:

if ((shirtImage) == 0)
    shirtImage = [shirtArray count];

The last item in an array has the index [arrayObj count] - 1.

In fact, you're setting the value of shirtImage anywhere in the range 1..arrayLength, where it should be in the range 0..arrayLength-1. I'd suggest you increment/decrement your index first, then check its bounds, then index into the array. For example:

case 2:
    // increment the index
    hatImage++; 

    // wrap around if you've gone beyond the bounds of the array
    if (hatImage == [hatArray count])
        hatImage = 0;

    // Index into the array
    [hat setImage:[hatArray objectAtIndex:hatImage]];
answered on Stack Overflow Jun 16, 2011 by Simon Whitaker • edited Jun 16, 2011 by Simon Whitaker
0

NSRangeException - that means you've overrun the bounds of an array.

An aside: You're declaring these as IBOutlet properties. What are you hooking them up to?

@property (nonatomic, retain) IBOutlet NSArray* hatArray;
@property (nonatomic, retain) IBOutlet NSArray* shirtArray;
@property (nonatomic, retain) IBOutlet NSArray* pantsArray;
@property (nonatomic, retain) IBOutlet NSArray* shoesArray;
answered on Stack Overflow Jun 16, 2011 by Abizern

User contributions licensed under CC BY-SA 3.0