I am using two UIPickers in a view.
first picker has 3 components and second has one.
but when I select items, it shows correct items from first picker but always return first item from second picker regardless of selected row.
Please help.
here is the code I am using.
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
if (pickerView == triplePicker)
return 3;
else {
return 1;
}
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if (pickerView == triplePicker) {
if (component == kColorComponent)
return[colorList count];
if (component == kClarityComponent)
return[clarityList count];
return[shapeList count];
}
else{
return [listPickerItems count];
}
}
-(NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
if (pickerView == triplePicker) {
if (component == kColorComponent)
return [colorList objectAtIndex:row];
if (component == kClarityComponent)
return [clarityList objectAtIndex:row];
return [shapeList objectAtIndex:row];
}
else{
return [listPickerItems objectAtIndex:row];
}
}
in buttonpressed event I have following for second picker to return the item selected:
NSInteger pickrow = [listPicker selectedRowInComponent:0];
NSString *picked = [listPickerItems objectAtIndex:pickrow];
I would definitely suggest using two separate delegates to handle two pickers.
Aside from that, I'm going to guess that you're using Interface Builder to set up your view. If that's the case check if you have properly linked your listPicker with your File's Owner. If listPicker would be nil, then selectedRowInComponent: would always return null (0 for NSInteger), hence would always select the first item in your array.
EDIT: Some sample code for separate delegates:
You need to create a second class to be your delegate, like this:
FirstPickerDelegate.h
#import <Foundation/Foundation.h>
#class UntitledViewController;
#interface FirstPickerViewDelegate : NSObject <UIPickerViewDelegate, UIPickerViewDataSource> {
NSArray* values;
IBOutlet UntitledViewController* viewController;
}
-(void) loadData;
#property (nonatomic, retain) NSArray* values;
#property (nonatomic, assign) IBOutlet UntitledViewController* viewController;
#end
FirstPickerViewDelegate.m
#import "FirstPickerViewDelegate.h"
#implementation FirstPickerViewDelegate
#synthesize values;
#synthesize viewController;
-(id) init
{
if ( self = [super init] )
{
[self loadData];
}
return self;
}
-(void) loadData
{
NSArray* array = [[NSArray alloc] initWithObjects:#"first", #"second", #"third", nil];
self.values = array;
[array release];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [values count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [values objectAtIndex:row];
}
-(void) dealloc
{
self.values = nil;
[super dealloc];
}
#end
Your ViewController (UntitledViewController here, sorry about the name):
#import <UIKit/UIKit.h>
#class FirstPickerViewDelegate;
#interface UntitledViewController : UIViewController {
IBOutlet UIPickerView* firstPicker;
IBOutlet FirstPickerViewDelegate* firstDelegate;
}
#property (nonatomic, retain) IBOutlet UIPickerView* firstPicker;
#property (nonatomic, retain) IBOutlet FirstPickerViewDelegate* firstDelegate;
#end
Basically you need to drop an NSObject on your object list, and change it's class to FirstPickerViewDelegate, then make connections like this:
I feel I overelaborated this time, but I'm in a good mood today so whatever :P
About the main question: double check that listPicker is not nil at the time of pressing the button, if it is not, try to use
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
to track down the error.
Related
I am trying to make a UIPickerView with data #"0", #"1", #"2", #"3"... display on rows,
it will be a 2 columns pickerView.
here is my code:
this is .h file
#import <UIKit/UIKit.h>
#interface CustomNumberViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
#property (strong, nonatomic) IBOutlet UIPickerView *numberPicker;
#property(strong, nonatomic)NSArray *listOfNumbers;
#property (strong,nonatomic)NSString *numberOfFirstColumn;
#property(strong,nonatomic)NSString *numberOfSecondColumn;
#end
this is .m file
#import "CustomNumberViewController.h"
#interface CustomNumberViewController ()
#end
#implementation CustomNumberViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
//UIView background
UIGraphicsBeginImageContext(self.view.frame.size);
[[UIImage imageNamed:#"pickerbackground.png"] drawInRect:self.view.bounds];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
//init picker
self.numberPicker.showsSelectionIndicator = TRUE;
self.listOfNumbers = [[NSArray alloc] initWithObjects:#"0",#"1",#"2",#"3",nil];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//Number of rows to display in each component
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if (component==0) {
return [self.listOfNumbers count];
}
return [self.listOfNumbers count];
}
//Number of columns to display
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
//define what to display in each rows and columns
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (component==0) {
return [self.listOfNumbers objectAtIndex:row];
}
return [self.listOfNumbers objectAtIndex:row];
}
//selected number to be stored in nsstring
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if (component==0) {
self.numberOfFirstColumn = [self.listOfNumbers objectAtIndex:row];
}
self.numberOfSecondColumn = [self.listOfNumbers objectAtIndex:row];
}
#end
My problem is if I try to run the app, the UIPickerView isn't filled with any data... so absolutely empty....
and if i try to scull the 'selected indicator', app will crash at once...
this is the error msg ->
Assertion failure in -[UITableViewRowData rectForRow:inSection:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableViewRowData.m:1630
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for rect at invalid index path ( 2 indexes [0, 0])'
any suggestions ? thanks
It looks like you are not creating your UIPickerView in code. Did you make sure that the delegate and data source of the picker is the class you are trying to create it in? If it is not, it will not know what you want to have in it.
Ok I am having trouble figuring out how to approach this.
I have a UITextField which I add to a UITableView dynamically according to the definitions of a XML file, in the XML file I may specify a list as one of the data types and what I do then is add a UIPickerView that displays the list to the inputView of my specific UITextField.
What I am having trouble with is figuring out how to take the selected value from the UIPickerView and add it to the text property of my UITextField
My UIPickerView is a custom class but I added no extra functionality I only overrode it to make it possible to pass a datasource to the UIPickerView as a property.
Here is my PickerViewDataSourceAndDelegate.h
#import <Foundation/Foundation.h>
#interface PickerViewDataSourceAndDelegate : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource>
#property (nonatomic, strong) NSMutableArray *pickerData;
#end
And it's .m file
#import "PickerViewDataSourceAndDelegate.h"
#implementation PickerViewDataSourceAndDelegate
#synthesize pickerData;
-(id)init {
if (self = [super init])
{
self.pickerData = [[NSMutableArray alloc] init];
}
return self;
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return [self.pickerData count];
}
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [self.pickerData objectAtIndex:row];
}
#end
This is how I add the UITextField with the UIPickerView as inputView
for(NodeProperty *nodeproperty in node.properties)
{
if(nodeproperty.flowDirection == (FlowDirection*)Output)
{
if([nodeproperty.typeName isEqualToString:#"System.String"] && nodeproperty.extendedType == (ExtendedType*)None && [nodeproperty.enumValues count] == 0)
{
...
}
else if([nodeproperty.typeName isEqualToString:#"System.String"] && nodeproperty.extendedType == (ExtendedType*)MultilineText && [nodeproperty.enumValues count] == 0)
{
...
}
else if([nodeproperty.typeName isEqualToString:#"System.Boolean"] && nodeproperty.extendedType == (ExtendedType*)None && [nodeproperty.enumValues count] == 0)
{
...
}
else if([nodeproperty.typeName isEqualToString:#"System.Double"] && nodeproperty.extendedType == (ExtendedType*)None && [nodeproperty.enumValues count] == 0)
{
...
}
else if([nodeproperty.typeName isEqualToString:#"System.String"] && nodeproperty.extendedType == (ExtendedType*)None && [nodeproperty.enumValues count] > 0)
{
UILabel *fieldLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, 290, 20)];
fieldLabel.text = nodeproperty.name;
[rowsInSectionLabels addObject:fieldLabel];
PickerViewDataSourceAndDelegate *pickerDataDel = [[PickerViewDataSourceAndDelegate alloc] init];
pickerDataDel.pickerData = nodeproperty.enumValues;
pickerDataDel.dataSource = pickerDataDel;
pickerDataDel.delegate = pickerDataDel;
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(5, 25, 290, 30)];
[textField setBorderStyle:UITextBorderStyleRoundedRect];
textField.inputView = pickerDataDel;
[rowsInSection addObject:textField];
}
else
{
....
For space I omitted some of the space, if some things are unclear I will gladly explain.
Every thing works perfectly with no exceptions, I just want to get the selected value out of the picker
See the picker view delegate protocol. Implement this method:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
In here, you can get the appropriate value from the model and update your text field.
To work out which is the current text field, you'd need to find out which of the text fields is the first responder.
Have all of the text fields in an IBOutletCollection or array, iterate through them and find the one which is first responder.
Or, if you have text field delegates, you can set an ivar for the current text field in the didBeginEditing delegate method, and use this in the picker view delegate method above.
I found my own solution that words like a charm, I had to create a delegate method to pass the value back to my UITextField.
First I declared a protocol in my PickerViewDataSourceAndDelegate.h
#protocol PickerRowSelected
-(void) selectedARowAndValueIs:(NSString*)aValue;
#end
Then I added a member:
id <PickerRowSelected> adelegate;
and added a property
#property (nonatomic, strong) id<PickerRowSelected> adelegate;
I then added this function
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
[adelegate selectedARowAndValueIs:[self.pickerData objectAtIndex:row]];
}
And in the controller that contains the textfield I added:
pickerDataDel.adelegate = self;
And implemented my new delegate method
-(void) selectedARowAndValueIs:(NSString *)aValue
{
UITextField *aview = (UITextField*)[self.view findViewThatIsFirstResponder];
aview.text = aValue;
}
See my answer on this question for finding the view that is the first responder
Find View that is the firstresponder
Use -[UIPickerView selectedRowInComponent:] to determine which row is selected, and then return the object at that index within your data array.
- (void)pickerView:(UIPickerView *)pickerView1 didSelectRow: (NSInteger)row inComponent:(NSInteger)component {
NSInteger selectedRow = [pickerView1 selectedRowInComponent:0];
NSString *selectedPickerRow=[yourArrayOfElements objectAtIndex:selectedRow];
// Handle the selection
}
Pass the String to the Text Field
I'm new to iOS dev, so this is probably easy to fix. I have a custom view controller in which I'm adopting the protocols to control a UIPickerView in a nib. Everything works fine unless, in the iPad simulator, I scroll the picker beyond the first item in the list or the last item in the list and release. It kicks the following error:
Thread 1: Program received signal: "EXC_BAD_ACCESS"
on this line of my main.m class:
int retVal = UIApplicationMain(argc, argv, nil, nil);
Relevant code follows:
ViewController.h
#interface BirdColorViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> {
IBOutlet UIPickerView *birdColorPicker;
NSArray *birdColors;
}
#property (nonatomic,retain) IBOutlet UIPickerView *birdColorPicker;
Viewcontroller.m
- (void)dealloc
{
[birdColorPicker release];
[super dealloc];
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
birdColors = [NSArray arrayWithObjects:#"Blue",#"Yellow",#"Red",nil];
birdColorPicker.delegate = self;
birdColorPicker.dataSource = self;
}
...
#pragma mark - UIPickerViewDataSource methods
//(UIPickerView *)thePickerView
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [birdColors count];
}
#pragma mark - UIPickerViewDelegate methods
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [birdColors objectAtIndex:row];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
// Set value in prefs/model
}
Try:
birdColors = [[NSArray alloc] initWithObjects:#"Blue",#"Yellow",#"Red",nil];
instead of birdColors = [NSArray arrayWithObjects:#"Blue",#"Yellow",#"Red",nil];
Make birdColors a property also (nonatomic, retain) like you do with the pickerView.
Your array is not being retained, so you're accessing zombie memory.
Set NSZombieEnabled=YES in the properties/General panel of your Executable. That will tell you exactly what is being accessed.
I have two UIPickerViews set up on one view under the same view controller. The picker's seem to be populated with values as expected. I also have a label for each picker. The label updates with each value change, but the value displayed on the label is not correct. It's always off by 10. The codes are below.
Interface:
#import <UIKit/UIKit.h>
#import "InfoViewController.h"
#interface TransactionsViewController : UIViewController {
//Deposit
NSMutableArray *depositArray;
IBOutlet UIPickerView *depositPicker;
IBOutlet UILabel *depositLabel;
//Send
NSMutableArray *sendArray;
IBOutlet UIPickerView *sendPicker;
IBOutlet UILabel *sendLabel;
}
#property (nonatomic, retain) NSMutableArray *depositArray;
#property (nonatomic, retain) IBOutlet UIPickerView *depositPicker;
#property (nonatomic, retain) NSMutableArray *sendArray;
#property (nonatomic, retain) IBOutlet UIPickerView *sendPicker;
#property (nonatomic, retain) IBOutlet UILabel *depositLabel;
#property (nonatomic, retain) IBOutlet UILabel *sendLabel;
#end
Implementation:
#import "TransactionsViewController.h"
#implementation TransactionsViewController
#synthesize depositArray;
#synthesize depositPicker;
#synthesize sendArray;
#synthesize sendPicker;
#synthesize depositLabel;
#synthesize sendLabel;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *dollarsArray = [[NSMutableArray alloc] init];
for (int i = 5; i <= 100; i+=5)
{
NSString *item = [[NSString alloc] initWithFormat:#"%i", i];
[dollarsArray addObject:item];
[item release];
}
self.depositArray = dollarsArray;
self.sendArray = dollarsArray;
[dollarsArray release];
}
// Pickers
#pragma mark - Pickers
#pragma mark Pickers Data Source Methods
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 2;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if(pickerView == depositPicker) {
switch(component) {
case 0:
return 1;
break;
case 1:
return [depositArray count];
break;
default:
break;
}
}
else if(pickerView == sendPicker) {
switch(component) {
case 0:
return 1;
break;
case 1:
return [sendArray count];
break;
default:
break;
}
}
return 0;
}
-(CGFloat)pickerView:(UIPickerView*)pickerView widthForComponent:(NSInteger)component {
switch (component) {
case 0:
return 50;
break;
case 1:
return 100;
break;
default:
break;
}
return 0;
}
#pragma mark Pickers Delegate Methods
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if(pickerView == depositPicker) {
switch(component) {
case 0:
return #"$";
break;
case 1:
depositLabel.text=[depositArray objectAtIndex:row];
return [depositArray objectAtIndex:row];
[depositLabel release];
break;
default:
break;
}
}
else if(pickerView == sendPicker) {
switch(component) {
case 0:
return #"$";
break;
case 1:
return [sendArray objectAtIndex:row];
break;
default:
break;
}
}
return 0;
}
//Pickers End
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[depositArray release];
[send release];
[super dealloc];
}
#end
Everything, such as the sendLabel, is not set up yet. As you can see, the depositLabel automatically updates with the selected row, however, the value is not updating to the correct value. I'm not sure if it's my implementation of the label or the picker itself that is the problem.
I'd appreciate some inputs. Thanks.
The titleForRow method is just where you're supposed to return the text for the row. In your titleForRow, it doesn't make sense to set the label text there (nor do I think should you release it). The "return 0" at the end of titleForRow may also cause problems.
To handle an actual select in a picker, use the didSelectRow method.
I have a xib in which I have added a UIViewController named delta. The view under delta is controlled by the delta viewcontroller, not the file owner. On the delta view, I have a UIViewPicker. My issue is that I am programming in the UIPickerView in the deltaviewcontroller and I'm issuing deltaviewcontroller as the delegate and data source for the UIPickerView. Everything should work, but when I load the deltaviewcontroller's view, the application crashes. If I carry out everything the same way under the file's owner view, it works fine. I'm wondering if there is really a way to make the UIPickerView work with a UIViewController and no necessarily a file's owner.
For references, the code:
Header
#interface DeltaViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> {
NSMutableArray *arrayNo;
IBOutlet UIPickerView *pickerView;
}
#property (nonatomic, retain) UIPickerView *pickerView;
#property (nonatomic, retain) NSMutableArray *arrayNo;
#end
Implementation
#import "DeltaViewController.h"
#implementation DeltaViewController
#synthesize pickerView;
#synthesize arrayNo;
- (void)viewDidLoad
{
NSMutableArray *dollarsArray = [[NSMutableArray alloc] init];
for (int i = 0; i < 100; i++)
{
NSString *item = [[NSString alloc] initWithFormat:#"%i", i];
[dollarsArray addObject:item];
}
self.arrayNo = dollarsArray;
[dollarsArray release];
}
#pragma mark -
#pragma mark Picker Data Source Methods
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [arrayNo count];
}
#pragma mark Picker Delegate Methods
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [arrayNo objectAtIndex:row];
}
- (void)dealloc {
[arrayNo release];
[pickerView release];
[super dealloc];
}
#end
Please point out if I'm doing anything wrong. Help is much appreciated.
If you search how to add a UIPickerView in a UIView, just check out the Apple sample code for UIPickerView. I think it's one of the best ways learning to use the different classes correctly. There are five project which includes an UIPickerView. Here's the link
UIPickerView class reference and sample code
Try doing
[self.view addSubview:pickerView];
in your viewDidLoad method.