Search code examples
iosobjective-cios7uipickerviewuipicker

Custom UIPickerView crash in iOS 7


I had made a Custom UIPickerView with three Components each showing label on Selection Indicator which is working fine in iOS 6.

But I am getting a crash in iOS 7.

Here is my code:

ViewController.h

#define kDaysComponent 0
#define kHoursComponent 1
#define kMinutesComponent 2

#import <UIKit/UIKit.h>
#import "LabeledPickerView.h"

@interface ViewController : UIViewController<UIPickerViewDataSource,UIPickerViewDelegate,UITextFieldDelegate>
{
    NSMutableArray *arrDays;
    NSMutableArray *arrHours;
    NSMutableArray *arrMinutes;

    LabeledPickerView *timePicker;
    IBOutlet UITextField *txtTimeLimit;
}

@property(nonatomic, retain) NSMutableArray *arrDays;
@property(nonatomic, retain) NSMutableArray *arrHours;
@property(nonatomic, retain) NSMutableArray *arrMinutes;

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize arrDays;
@synthesize arrHours;
@synthesize arrMinutes;

- (void)viewDidLoad
{

    self.arrDays = [[NSMutableArray alloc]initWithCapacity:100];
    for (NSInteger i = 0; i < 100; i++){
        [arrDays addObject:[NSString stringWithFormat:@"%d",i]];
    }
    //self.arrDays = arrDays;
    self.arrHours = [[NSMutableArray alloc]initWithCapacity:24];
    for (NSInteger i = 0; i < 24; i++){
        [arrHours addObject:[NSString stringWithFormat:@"%d",i]];
    }
    //self.arrHours = arrHours;
    self.arrMinutes = [[NSMutableArray alloc]initWithCapacity:60];
    for (NSInteger i = 0; i < 60; i++){
        [arrMinutes addObject:[NSString stringWithFormat:@"%d",i]];
    }
    //self.arrMinutes = arrMinutes;

    [self.navigationController setNavigationBarHidden:YES];

    [super viewDidLoad];


}

-(IBAction)Click:(id)sender{

    timePicker = [[LabeledPickerView alloc] init];
    timePicker.showsSelectionIndicator = YES;
    timePicker.dataSource = self;
    timePicker.delegate = self;
    [timePicker addLabel:@"Days" forComponent:kDaysComponent forLongestString:@"Hours"];
    [timePicker addLabel:@"Hours" forComponent:kHoursComponent forLongestString:@"Hours"];
    [timePicker addLabel:@"Mins" forComponent:kMinutesComponent forLongestString:@"Mins"];

    UIToolbar* toolbar = [[UIToolbar alloc] init];
    toolbar.barStyle = UIBarStyleBlackTranslucent;
    [toolbar sizeToFit];

    //to make the done button aligned to the right
    UIBarButtonItem *flexibleSpaceLeft = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
    UIBarButtonItem *flexibleSpaceRight = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

    UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneClicked:)];


    UIBarButtonItem *unlimitedButton = [[UIBarButtonItem alloc] initWithTitle:@"Unlimited" style:UIBarButtonItemStyleBordered target:self action:@selector(unlimitedClicked:)];

    [unlimitedButton setTintColor:[UIColor colorWithRed:100.0f/255.0f green:197.0f/255.0f blue:84.0f/255.0f alpha:1.0f]];

    UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStyleDone target:self action:@selector(cancelClicked:)];

    [toolbar setItems:[NSArray arrayWithObjects:cancelButton,flexibleSpaceLeft,unlimitedButton,flexibleSpaceRight,doneButton, nil]];

    //custom input view
    txtTimeLimit.inputView = timePicker;
    txtTimeLimit.inputAccessoryView = toolbar;
}
-(void)doneClicked:(id) sender
{
    [txtTimeLimit resignFirstResponder]; //hides the pickerView

    NSInteger daysRow = [timePicker selectedRowInComponent: kDaysComponent];
    NSInteger hoursRow = [timePicker selectedRowInComponent: kHoursComponent];
    NSInteger minutesRow = [timePicker selectedRowInComponent: kMinutesComponent];
    NSString *days = [arrDays objectAtIndex:daysRow];
    NSString *hours = [arrHours objectAtIndex:hoursRow];
    NSString *minutes = [arrMinutes objectAtIndex:minutesRow];

    txtTimeLimit.text = [[NSString alloc] initWithFormat:
                         @"Expires in [%@] Days [%@] Hours [%@] Minutes.",days,hours,minutes];
    if ([txtTimeLimit.text isEqualToString:@""])
    {

    }
    else
    {

    }
}

-(void)cancelClicked:(id) sender
{
    [txtTimeLimit resignFirstResponder]; //hides the pickerView
}

-(void)unlimitedClicked:(id) sender
{
    [txtTimeLimit resignFirstResponder]; //hides the pickerView
    txtTimeLimit.text = @"Select Time Limit";
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark Picker View Delegate

- (NSInteger)numberOfComponentsInPickerView:(LabeledPickerView *)pickerView
{
    return 3;
}

- (NSInteger)pickerView:(LabeledPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    if (component == kDaysComponent)
    {
        return [self.arrDays count];
    }
    else if (component == kHoursComponent)
    {
        return [self.arrHours count];
    }
    else if (component == kMinutesComponent)
    {
        return [self.arrMinutes count];
    }
    return 0;
}

- (NSString *)pickerView:(LabeledPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    if (component == kDaysComponent)
    {
        NSLog(@"%@",[arrDays objectAtIndex:row]);
        return [self.arrDays objectAtIndex:row];
    }
    else if (component == kHoursComponent)
    {
        NSLog(@"%@",[arrHours objectAtIndex:row]);
        return [self.arrHours objectAtIndex:row];
    }
    else if (component == kMinutesComponent)
    {
        return [self.arrMinutes objectAtIndex:row];
    }
    return 0;

}

#pragma mark TEXT FIELD DELEGATE

- (BOOL)textFieldShouldBeginEditing:(UITextField *)aTextField
{
    [self Click:aTextField];
    return YES;

}

I am showing UIPickerView as an input view for UITextField and each time I am getting this error in iOS 7 only:

Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 5 beyond bounds [0 .. 2]'

I don't know what's wrong with it. Can anyone please help me on this?


Solution

  • Your crash is telling you what the problem is:

    -[__NSArrayM objectAtIndex:]: index 5 beyond bounds [0 .. 2]'

    You are trying to get a value of object at the index 5 when your array only contains 3 objects.

    Put a break point in and check the arrays contain what you expect and the component value is what you expect.