Search code examples
iosuipickerviewexc-bad-access

Building a UIPickerView Util class


I'm trying to learn iOS from an entirely Android background. I would like to build a UIPickerView Util class that can be reused over and over again as a separate class throughout my app and I'm receiving the EXC_BAD_ACCESS message and I'm not sure why. So I have two questions:

  1. I've not seen anything about separating this as a different class, is this because this is an improper way to handle this problem?

  2. What's wrong with this basic (mostly generated) code that would be giving me the EXC_BAD ACCESS message? I've read that this is related to memory issues. I'm using ARC so why is this an issue?

Here are the beginnings of the class that I'm trying to build.

Header file

#import <UIKit/UIKit.h>

@interface PickerTools : UIViewController<UIPickerViewDelegate>

@property (strong, nonatomic)UIPickerView* myPickerView;

-(UIPickerView*)showPicker;

@end

Implementation file

#import "PickerTools.h"

@implementation PickerTools

@synthesize myPickerView;

- (UIPickerView*)showPicker {
    myPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 200, 320, 200)];
    myPickerView.delegate = self;
    myPickerView.showsSelectionIndicator = YES;
    return myPickerView;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow: (NSInteger)row inComponent:        (NSInteger)component {
    // Handle the selection
}

// tell the picker how many rows are available for a given component
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    NSUInteger numRows = 5;

    return numRows;
}

// tell the picker how many components it will have
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 1;
}

// tell the picker the title for a given component
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
    NSString *title;
    title = [@"" stringByAppendingFormat:@"%d",row];

    return title;
}

// tell the picker the width of each row for a given component
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
    int sectionWidth = 300;

    return sectionWidth;
}

@end

Here's how I'm calling it from a method in a UITableViewController class:

PickerTools *picker = [[PickerTools alloc]init];
[[self view]addSubview:[picker showPicker]];

Solution

  • What are you doing with showPicker? showPicker is misleading because it doesn't actually show. It only returns a pickerView with a frame. At some point you need to add it to a view using addSubview or use a UIPopoverController or something.

    If you are just creating your view controller class within the scope of a method, then it is getting released as soon as that method is done running. Then all bets are off. The picker is trying to access the delegate (which is the view controller) but the view controller is nowhere to be found because it was released.

    You'll have to post some usage code. By itself, this code should work, but it's how you're using it.

    Also, you don't have to use a UIViewController just to "control" a simple view. Consider making a custom class and just sublcass NSObject.

    EDIT: After looking at your posted code my suspicions were correct. You need to "retain" your PickerTools instance. Meaning, you need to save the "picker" variable (misleading again) as a strong property on the calling view controller. It gets released right after you're adding the pickerview as a subview. The pickerView is alive because it's being retained by it's superview but the object that holds it (the delegate "picker") is dead. Make sense?