Custom UIPickerView text formatting

UIPicky

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

pickerI 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.