0

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?

Community
  • 1
  • 1
Ajay
  • 1,622
  • 20
  • 36
  • on what line/method do you get the crash? – alex-i Nov 26 '13 at 08:40
  • in delegate method pickerView titleForRow – Ajay Nov 26 '13 at 08:42
  • the code seems fine. My only guess is that you're removing objects from your arrays at some point (or re-setting the arrays to something else), but I can't see that anywhere in the code. – alex-i Nov 26 '13 at 08:52
  • I am not removing objects from arrays and I have posted the whole code as you can see. I am stuck at this issue right now. – Ajay Nov 26 '13 at 08:56
  • Well.. there's obviously something missing somewhere (all your arrays should have more than 24 items according to your code). You'll need to give some more info if you want people to be able to help you. Start by giving the exact line of code that produces the crash. Put a `NSLog` or a breakpoint and have a look at the contents of your crashing array, before it crashes. Without more info we can only throw with guesses. – alex-i Nov 26 '13 at 14:25

3 Answers3

0

Please try to set txtTimeLimit.inputView after delays like one second.

[self performSelector:@selector(setInputView:) withObject:timePicker afterDelay:1];


- (void)setInputView:(LabeledPickerView*)picker {
   txtTimeLimit.inputView = picker;
}

I think it's something doing with the animation....

LeverkusenFan
  • 293
  • 4
  • 8
0

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.

CW0007007
  • 5,681
  • 4
  • 26
  • 31
-1

You have to concern in few things,

First is the delegate and datasource method. If u get the warning on delegate and datasource then correct the code like this

timePicker.dataSource = (id)self;
timePicker.delegate = (id)self;

Then Check the array. Hopefully it will solve your problem.

Shyantanu
  • 681
  • 1
  • 12
  • 30
  • Thanks but still not working..and I have already made clear that I am getting this error only in iOS 7. Its working fine with iOS 6 – Ajay Nov 26 '13 at 09:03
  • @Ajay plz go for this link .. http://stackoverflow.com/questions/19125057/uipicker-and-uiactionsheet-no-longer-working-ios7 – Shyantanu Nov 26 '13 at 09:07
  • Checked your link but it does not relate my question in anyway. They are talking about putting a picker in an action sheet. But I had made my custom picker by subclassing standard UIPickerView. – Ajay Nov 26 '13 at 09:14