
For one of my apps, I need a UIPickerView (the scroll wheel selection tool). I needed to be able to change the appearance of the text in the picker, which is only possible by attaching a UILabel to each row instead of a NSString. It also requires a different method in the delegate.
To use NSStrings in a picker, you implement this method in the delegate:
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
To attach a UILabel instead of a NSString, you implement this method in place of the previous one:
- (UIView *)pickerView:(UIPickerView *)pickerView
viewForRow:(NSInteger)row
forComponent:(NSInteger)component
reusingView:(UIView *)view
I had pieced together my method to attach a UILabel with custom formatting, and it was working… somewhat. Whenever I would scroll past four or five rows, my app would freeze and I would get an error saying “EXC_BAD_ACCESS” in the console. After reading a dozen different support threads and documentation pages on this subject, I finally found the answer. See my completed method below (stripped of any terminology that would give my app away, of course). The method is assuming your text data is coming from a NSArray called pickerDataArray.
The key was that I was releasing the label (via autorelease) at the end of the method, when I wasn’t supposed to. Read why in the comment at the end of the method.
- (UIView *)pickerView:(UIPickerView *)pickerView
viewForRow:(NSInteger)row
forComponent:(NSInteger)component
reusingView:(UIView *)view {
UILabel *pickerLabel = (UILabel *)view;
if (pickerLabel == nil) {
CGRect frame = CGRectMake(0.0, 0.0, 80, 32);
pickerLabel = [[[UILabel alloc] initWithFrame:frame] autorelease];
[pickerLabel setTextAlignment:UITextAlignmentLeft];
[pickerLabel setBackgroundColor:[UIColor clearColor]];
[pickerLabel setFont:[UIFont boldSystemFontOfSize:15]];
}
[pickerLabel setText:[pickerDataArray objectAtIndex:row]];
return pickerLabel;
}
// It is NOT "return [pickerLabel autorelease];" because if the view
// you return is different from the one used in the previous row,
// the method will release the previous one for you. If you use
// "autorelease," you will see the EXC_BAD_ACCESS error and your
// picker will freeze when scrolling.
No related posts.
providing that none of your other code changed and all you did was remove the autorelease from the return statement. You autorelase pickerLabel on the same line that you alloc so an autorelease on the return line would try and release the same object a second time resulting in fun errors.
You are right! I didn’t see that before… I did find in the documentation that this method (pickerView: viewForRow: forComponent: reusingView:) does in fact release it for you if you forget to do so. Once I saw that, I assumed that was what was happening, and didn’t continue searching through my own code. Whoops!
hmm me too have the same prob thanx
hi,
i came across this problem, did not get how to get rid of the EXE_BAD_ACCESS & freeze of the pickerView…
is it working for you without the autorelease?
thanks for any additional help/details.
Yes, it’s working great so far. I haven’t gotten a chance to develop it much further (my SimpleMap plugin has taken up most of my time lately) but I have done a little more with it. Finding that autorelease and removing it was a godsend.
Hi, I am also facing the same problem. Its working fine. Thanks.