iOS Programming Recipe 7: Using the UIPickerView

The UIPickerView can be a frustrating element for a new iOS programmer. I know first hand as I was just recently there.

For this example I’m going to create a simple color picker. from the picker we can select a color and the RGB value will print to the screen. Seems easy enough? right? Let’s get to it!

Assumptions

  • You Are familiar with Xcode and the storyboard
  • you know how to create a single view controller

Setting up the Storyboard

First start out with a single view controller and title it whatever you like. I titled mine “PickIt”.

From the Storyboard drag a new UIPickerView object on to the view from the Object Library in the bottom right hand corner of the screen.

Create some new labels titled “Color Picker”, “You Chose:”, and “Nothing”. Arrange all of these elements as seen on the scren below. Optionally you can choose a background for your view too.

Laying out UIPickerView on Storyboard

 

Making the Connections

create an outlet for the “Nothing” Label by clicking and dragging it into the ViewController.h file between #import and @end. when prompted give it a name of “color”.

Creating Outlets

 

Naming Outlets

create another outlet for the picker titled “picker”. when you’re done your viewController.h file should look like the following:


#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (strong, nonatomic) IBOutlet      UILabel *color;
@property (strong, nonatomic) IBOutlet      UIPickerView *picker;

@end

since we’re looking at the viewController.h, let’s go ahead and let the controller know we’re conforming to the UipickerView data source and delegate protocols. To do this, add the following text at the end of the @interface line: <UIPickerViewDataSource,UIPickerViewDelegate>.

now your ViewController.h file should look like this


#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UIPickerViewDataSource,UIPickerViewDelegate>

@property (strong, nonatomic) IBOutlet UILabel *color;

@property (strong, nonatomic) IBOutlet UIPickerView *picker;

@end

Now we’re ready to implement the data source and the delegate for the UIPickerView.

Implementing the Data Source

You may have noticed that when we added the text “<UIPickerViewDataSource,UIPickerViewDelegate>” a warning popped up in the ViewController.m file:

Warning message for protocol

This is telling us something important! It’s saying “Hey! I was told we are conforming to the data source and delegate protocols but I don’t see any of the required methods.” The warning is even nice enough to tell us which ones are needed. For this example the delegate methods is optional, but the picker wouldn’t do much without them.

To find out what methods a data source needs, go ahead and command click the UIPickerViewDataSource text located here:

where to click for UIPickerViewDataSource class

This will take you to the UIpickerView.h file. In this file, you’ll see the following section:


@protocol UIPickerViewDataSource
@required

// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;

// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component;
@end

This section explicitly calls out which methods you need to have in your implementation file. So go ahead and copy everything between the @required and @end and paste them into your ViewController.m file before @end. Then replace the simi-colons with open and close brackets like this:


// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{

}

// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component
{

}
@end

Alright, we’re almost done with the data source implementation. The last thing we’ll need to do is set the return values of each.

The first method “numberOfComponentsInPickerView” expects an integer value. This lets the picker know how many columns it will need. We’ll only need on so set the return value to 1.

The second method “numberOfRowsInComponent” is asking for the number of rows in a picker. we’ll want to use 6 colors so go ahead and put a return value of 6 in there.

Now your methods should look like this:


// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 1;

}

// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component
{
    return 6;

}

Implementing the Delegate

As you did before with the datasource. Command click the UIPickerViewDelegate from the viewController.h file. This time you’ll see a number of delegates. For the purpose of this tutorial you’ll only need two of those. We’re gonna use the titleForRow method and the didSelectRow method at the end of your viewController.m file before the @end. you should have the following methods:


-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row   forComponent:(NSInteger)component
{

}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row   inComponent:(NSInteger)component
{

}

Now we’re ready to pass in some values, but first we’ll need to create an array to hold these values. So go back to your .h file and create a new array titled “colorArray” like so:


@interface ViewController : UIViewController <UIPickerViewDataSource,UIPickerViewDelegate>

@property (strong, nonatomic) IBOutlet UILabel *color;
@property (strong, nonatomic) IBOutlet UIPickerView *picker;
@property (strong, nonatomic)          NSArray *colorArray;

@end

now in the viewDidLoad method of your implementation file allocate and initialize your array:


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.colorArray  = [[NSArray alloc]         initWithObjects:@"Blue",@"Green",@"Orange",@"Purple",@"Red",@"Yellow" , nil];
}

And finally return the array value at index equal to the row number in our titleForRow method. So this method basically steps through each item in our array and sets it to the next row.


-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row   forComponent:(NSInteger)component
{

  return [self.colorArray objectAtIndex:row];

}

Now We’ll add a little logic to the other delegate method “didSelectRow” to handle the RGB Color label. Here I’ll use a case statement to check which row was selected and based on that I’ll know which color it was.


- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row   inComponent:(NSInteger)component{

    NSLog(@"Selected Row %d", row);
    switch(row)
    {

        case 0:
            self.color.text = @"Blue #0000FF";
            self.color.textColor = [UIColor colorWithRed:0.0f/255.0f green: 0.0f/255.0f blue:255.0f/255.0f alpha:255.0f/255.0f];
            break;
        case 1:
            self.color.text = @"Green #00FF00";
            self.color.textColor = [UIColor colorWithRed:0.0f/255.0f green: 255.0f/255.0f blue:0.0f/255.0f alpha:255.0f/255.0f];
            break;
        case 2:
            self.color.text = @"Orange #FF681F";
            self.color.textColor = [UIColor colorWithRed:205.0f/255.0f green:   140.0f/255.0f blue:31.0f/255.0f alpha:255.0f/255.0f];
            break;
        case 3:
            self.color.text = @"Purple #FF00FF";
            self.color.textColor = [UIColor colorWithRed:255.0f/255.0f green:   0.0f/255.0f blue:255.0f/255.0f alpha:255.0f/255.0f];          
            break;
        case 4:
            self.color.text = @"Red #FF0000";
            self.color.textColor = [UIColor colorWithRed:255.0f/255.0f green:   0.0f/255.0f blue:0.0f/255.0f alpha:255.0f/255.0f];
            break;
        case 5:
            self.color.text = @"Yellow #FFFF00";
            self.color.textColor = [UIColor colorWithRed:255.0f/255.0f green:   255.0f/255.0f blue:0.0f/255.0f alpha:255.0f/255.0f];
            break;
    }

}

In this case statement we’re setting the color of the text and giving the RGB value. Now If we try to run this at this point It will fail because we have not yet hooked our picker data source and delegate to anything.

Setting the Data Source and Delegate

Go back to the storyboard and select the picker. With the picker selected go to the connections inspector in top right hand corner and control click the circle next to delegate and drag all the way over to the view controller item document outline:

Connecting Delegate and Data source to UIPickerView

Repeat this for the data source.

That’s It! Now when you run the Simulation you should see something like this:

Finished ColorPicker

Wrap Up

Now you have a basic understanding of the picker. We’ll be revisiting this subject in the future to show you how to do multiple columns and multiple fields.

Another thing to note: In the numberOfRowsInComponent data source method we returned a value of 6, I did this as it is more demonstrative. In the future you should use return [self.colorArray count] in it’s place.

About Joe Hoffman

I am An Electrical Engineer that spends a lot of my off time doing web development and other programming. Currently I am trying to expand my knowledge with iOS and I find that writing tutorials helps me learn more thoroughly as well as provide some useful info to others.

Comments

  1. Hi Joe. Thanks for your articles!
    I understand that you tried to keep this example simple, but anyway I’d suggest making the ‘self.colorArray’ an array of NSDictionary objects (or even better, objects of a dedicated @interface) to keep the colors-related information together.

    • Joe Hoffman says:

      Hi Eugene,

      I thought I already responded to this. Sorry bout that! Thanks for the feedback! I think that would be a good idea! I was a little more careless with some of my first posts, so I don’t have the source code anymore to update from. I would encourage anyone reading this to give it a try though.

  2. I have question on the way pickerView object manages data source. Is there a way to set pickerView object with the data source and let it manages the data as one of its internal property with proper method to manipulate the data? From your example, it seems like we manage the data by our own with external object (Array in this case). It would be nice, if I can just ask the pickerView object to give me the selected item (either index or text or object), instead of having to go back to the array for look up.

    • Joe Hoffman says:

      Hi Noomy,

      I don’t think there is a way to have the picker store the data. You will alway have to reference an array, dictionary, or some other data object. You can get the text for the current index back from the pickerview though, but it would probably be just as easy to call the index from the array you used to populate the picker in the first place.

      • Thanks Joe for your help. I really appreciate for putting this cookbook up. This really helps getting start for the newbies.

        • Joe Hoffman says:

          No Problem Noomy!

          I have found this website to be rewarding so far. Not only do I get to help people out when I have time, but this is all helping me learn so much quicker. I only hope that if this site becomes more popular I can continue to be as interactive with my audience.

  3. hi,

    I tried to follow the steps but I hit some error. I believe that codes need to be added to viewDidLoad to initialive the delegate and dataSource.

    - (void)viewDidLoad
    {
    [super viewDidLoad];
    myPickerView.delegate = self;
    myPickerView.dataSource = self;
    }

    Please confirm if the above is correct.

    thanks,
    Nebi

    • Joe Hoffman says:

      Hi Nebi,

      In the last paragraph or so I describe how to set the delegate and datasource using the click and drag method. Both methods are equally applicable. since we are using storyboards, I chose to use the graphical method instead of the programatic method. I typically don’t see errors when I forget to set the delegate and datasource however, are you sure that’s the problem?

  4. Hi Joe, thanks for tutorial. I’m getting error when I run simul -

    “Terminating app due to uncaught exception ‘NSInvalidArgumentException’

    -reason: ‘-[UIView numberOfComponentsInPickerView: ]: unrecognized selector sent to instance’

    Any ideas? Thx

    • Joe Hoffman says:

      Hi Garmesh,

      If I had to guess it’s because the array you are trying to add to your picker view does not match the number of components you return in the numberOfComponentsInPickerView method.

    • Hi,
      I have the same problem. What did solve yours?

      • ..solved it myself by adding

        self.picker.delegate = self;
        self.picker.dataSource = self;

        to viewDidLoad as suggested in another post. I am not sure why my drag and drop method I started with failed though.

        Great tutorial by the way!

        • Joe Hoffman says:

          Good to hear Jonas!

          The click and drag method can give you issues if you add them to an element within the view rather than the view itself. Both ways are correct, these days I’ve been just setting the delegate in the viewDidLoad method as it is more clear.

          CHeers!

  5. Thank you so much for the tutorial. My first UIpicker that can run without any errors. I have tried so many different tutorials and most of the tutorials can only get it through half way because it was too complicated or different version of xcode.

    • Joe Hoffman says:

      Hi Jay!

      Glad you were able to get it up and going! Did you do this using Xcode 5 and iOS 7? I haven’t checked myself if this tutorial works on the new platform.

  6. I have a different problem with my picker. I want to use it in a different storyboard then the main one (View Controller). When I try and drag the picker to the .h file, it does not work, it only allows me to drag it from the main controller which is where I don’t want it. Do I need to use a different style of Controller?

  7. Ok, I must be missing something, none of my buttons work in the other Storyboards, only in the main controller. A’m I missing a way to link them to the .h or do you have to have a .h for each controller?

    • Joe Hoffman says:

      Yes, You should have a new UIVIewController class (one .h and .m) for every view you wish to interact with on the storyboard. Create a new class using the + button in the bottom left corner. choose objective-c class. subclass it with UIViewController and give it whatever name you wish. Then from the storyboard select the view you wish to connect to the new class and set the custom class from the identity inspector on top right of the Xcode environment.

  8. Hi Joe !
    I have a problem with my picker view in ios 7.
    How to Dismiss PickerView with Done button on UIToolBar?
    Unable to fire click event of done button in ios 7.

  9. Hay, I found an error in your code, in this part…..

    - (void)viewDidLoad
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.colorArray = [[NSArray alloc] initWithObjects:@”Blue”,@”Green”,@”Orange”,”@”Purple”,@”Red”,@”Yellow” , nil];
    }

    you have an extra ” before Purple: “@”Purple”,

    After ages of playing around I managed to fix this but as you can imagine it was such a small thing and as I’m new to picker views and coding it took me ages to spot.

    Thought id let you know so you can fix for others

    Kind Regards

    Rich

  10. Is there a setting to make it look nice? I’m not getting the 3D wheel.

    • Joe Hoffman says:

      Hi Jasper,

      you should see the default UIPicker controller. Perhaps you’ve set up the delegate or data source incorrectly.

      • Scott Latham says:

        I believe what you are seeing is the difference between iOS6 and iOS7. I have to completely rethink my level of respect for Jonny Ive’s if iOS7 is what he things is a modern design. Looks like Jobs really was the Master.

  11. JasperVaz says:

    It turns out iOS 7 flattened the picker, made it black and white, etc.. Thanks for the tutorial!

  12. hey joe, great tutorial! im new to programming with xcode so this helped alot! I needed UIPicker for people to select there shoe size (the first column says UK or US, then the second says women’s or mens and the third says actual number of shoe size!) then the app will convert it to inches by using a database i have, then multiplies that by 0.0833333. then on screen two, you enter a distance (feet) and it multiplies that by the answer of inches x 0.0833333. then on screen 3 it displays the answer. this tutorial helped greatly! i just want to know what is the color array supposed to do? (p.s im new to app developing. this is for a project for school.)

  13. So, I was looking at both this and http://nscookbook.com/2013/01/ios-programming-recipe-9-adding-multiple-columns-to-uipickerview/ and I was fiddling a bit with both of the codes. In my program I was hoping to use 4 columns with different arrays in each of them. However, when I run and start the Xcode thing, I just see a blank picker. Please help?

    Thank you

    • Joe Hoffman says:

      Hi Rockpath!

      I would probably guess that you forgot to connect your delegate and datasource. try this. self.(property name for picker).delegate = self in your viewDidLoad method.
      same goes for the datasource.

  14. Why in an example from xcode 4 does the delegate and datasource get the fileowner view controller and works yet in XCODE 5 the file owner gets concatanated or changed to just ‘view’. This makes your code above worthless. The code I have is just the same except for that and the new delegate in the .h.

    Is this a bug in XCODE that everyone is freaking about or is there something I don’t know as I can’t get the delegate to be view controller as per a working project i downloaded that works and I can’t add a new referencing outlet of Picker.
    WHY?WHY?WHY?

  15. IMPORTANT!!!! BEFORE ANY DATASOURCES OR DELEGATES ARE SELECTED.

    The solution for me was to select the View Controller so the outside is highlighted blue.
    Open the connections inspector.

    You then create a new referencing outlet by dragging the + onto the picker.

    It prompts for datasource and delegate. Do it for both. Now when you drag the datasource and delegate when you select the picker the owner will be View Controller and not View.

    All worked as should after that.

    • Joe Hoffman says:

      Hi Levko,

      Sorry I didn’t get here sooner. But yeah, Looks like you figured it out. I don’t recall this being so tricky in Xcode 4, but you must make sure that you are in fact selecting the view controller rather than some entity inside it. Sorry you had to beat your head against the wall to discover that, but I bet you remember it forever now ;)

  16. praveen says:

    thanks man its really easy to understand

  17. praveen says:

    Hi, I’m newbie, this very useful on how to use Picker.
    However, I got an error
    I’m working IOS7, and I got below error even after following your exact steps. The error that I received is below.

    [UIView numberOfComponentsInPickerView:]: unrecognized selector sent to instance

    However, after intializing data source and delegate in the ViewDidLoad as below, the error is gone.
    - (void)viewDidLoad
    {
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    // below two lines removed error.
    _picker.dataSource = self;
    _picker.delegate = self;

    //initialize colorarray with values
    self.colorArray = [[NSArray alloc] initWithObjects:@”Blue”,@”Green”,@”Orange”,@”Purple”,@”Red”,@”Yellow”, nil];

    }

    Thanks again for this help

  18. Thanks so much for sharing this. I’m a beginner, but have already worked with TableViewCells so this was very similar. I really appreciated your thorough description of the entire process. Love resources like this!

  19. Is it possible to have the same look and feel as that of iOS6?

    • Joe Hoffman says:

      Sure! anythings possible, but you would have a lot of work involved in subclassing it and creating your own, but this is not easily done.

Speak Your Mind

*

css.php
Privacy Policy