I added a UIPickerView to a UITableViewCell. I am adding about 5 entries to it. Now when I try to select a value, the - (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component function is called with the correct row. But on the scrren the UIPickerView "scrolls" back to the first element and does not stick to the selected value.
Anyone had the same problem?
EventSelectCell.h
#class EventSelectCell;
#protocol EventSelectCellDelegate <NSObject>
- (void)selectedEvent:(Event*)selectedEvent;
#end
#interface EventSelectCell : UITableViewCell <UIPickerViewDataSource, UIPickerViewDelegate>
#property (strong, nonatomic) id <EventSelectCellDelegate> delegate;
#property (weak, nonatomic) IBOutlet UIPickerView *selectWheel;
#end
EventSelectCell.m
#import "EventSelectCell.h"
#implementation EventSelectCell
{
EventManager* eventManager;
NSArray* listOfEvents;
}
- (void)awakeFromNib {
self.selectWheel.delegate = self;
self.selectWheel.dataSource = self;
// get the EventManger
eventManager = [EventManager sharedEventManager];
listOfEvents = [eventManager getListOfEvents];
[self.selectWheel reloadAllComponents];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return [listOfEvents count];
}
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
Event* selectedEvent = [listOfEvents objectAtIndex:row];
return [selectedEvent name];
}
- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
Event* selectedEvent = [listOfEvents objectAtIndex:row];
[self.delegate selectedEvent:selectedEvent];
}
#end
the delegate
- (void)selectedEvent:(Event*)selectedEvent {
[playersInGame removeAllObjects];
[playersInGame addObjectsFromArray:[self.eventManager getPlayersInEvent:selectedEvent onlyActive:YES]];
[selectedEvent setIsActive:[NSNumber numberWithInt:1]];
activeEvent = selectedEvent;
[self.tableView reloadData];
}
Okay, I found the problem. The UIPickerView is in a UITableViewCell. Whenever someone selected something with the UIPickerView I called [self.tableView reloadData], this caused the table to reload and also initialized the UIPickerView again.
Now I am just reloading a singel section in the table.
So I've followed everything this post Default Picker Value iphone says, but I can't seem to get my picker to work.
Here's my .m snippet:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.arrPercent = #[#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10",#"11",#"12",#"13",#"14",#"15",#"16",#"17",#"18",#"19",#"20",#"21",#"22",#"23",#"24",#"25",#"26",#"27",#"28",#"29",#"30",#"31",#"32",#"33",#"34",#"35",#"36",#"37",#"38",#"39",#"40",#"41",#"42",#"43",#"44",#"45",#"46",#"47",#"48",#"49",#"50"];
self.arrPeople = #[#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10",#"11",#"12",#"13",#"14",#"15",#"16",#"17",#"18",#"19",#"20"];
self.percent = [NSNumber numberWithInt:15];
self.people = [NSNumber numberWithInt:5];
self.strSubTotal = #"";
self.myPicker.dataSource = self;
self.myPicker.delegate = self;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//[self.myPicker selectRow:self.percent.integerValue inComponent:0 animated:YES];
[self.myPicker selectRow:5 inComponent:0 animated:YES];
[self.myPicker selectRow:5 inComponent:1 animated:YES];
[self.myPicker reloadAllComponents]; // tried commenting out this line with no luck
}
Here's my .h snippet:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface ViewController : UIViewController <UIPickerViewDataSource,UIPickerViewDelegate>
#property (nonatomic,strong) NSArray *arrPercent;
#property (nonatomic,strong) NSArray *arrPeople;
#property (strong, nonatomic) IBOutlet UIPickerView *myPicker;
#property (strong, nonatomic) NSString *strSubTotal;
#property (strong, nonatomic) NSNumber *percent;
#property (strong, nonatomic) NSNumber *people;
#end
Here's the delegate stuff, I think...
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 2;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component
{
if(component== 0)
{
return [self.arrPercent count];
}
else
{
return [self.arrPeople count];
}
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if(component == 0)
{
return [NSString stringWithFormat:#"%#%#", [self.arrPercent objectAtIndex:row], #"%"];
}
else
{
return [self.arrPeople objectAtIndex:row];
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if(component == 0)
{
self.percent = [self.arrPercent objectAtIndex:row];
}
else
{
self.people = [self.arrPeople objectAtIndex:row];
}
[self updateSubTotal:-3];
}
When I start the emulator, the picker doesn't animate to the position I tell it to. Am I doing anything wrong? Please help!
As it turns out, the error was that for some reason, the connection between the picker in the UI was disconnected with the code. I had to hold the Control key while dragging the picker from the UI to the .h file.
I saw this because I noticed a little "empty button icon" next to the method declaration in the .h file. Once Xcode understood that the picker is controlled by the piece of code, everything works as expected.
Thank you so much!
I have created a customed UITableViewCell that contains a PFObject property and a button. I want the button to add this object on a NSMutableArray and pass this Array to another UIViewController. The problem is that I can't implement the prepareForSegue method into custom UITableViewCell so when I display the array in restoCardConfirmationVC I always get an empty array.
This is my code :
#import "boxTableViewCell.h"
#import "RestoCardConfirmationViewController.h"
#import "RestauCardViewController.h"
#implementation boxTableViewCell {
NSMutableArray *_pickerPlace;
RestauCardViewController *_restoCardVC;
RestoCardConfirmationViewController *_restoCardConfirmationVC;
}
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return _pickerPlace.count;
}
- (NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [_pickerPlace objectAtIndex:row];
}
- (IBAction)select:(id)sender {
NSLog(#"the select box is : %#",_box);
[_restoCardConfirmationVC.boxesCommande addObject:_box];
self.select.enabled = NO;
}
#end
RestaCardConfirmation.h
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#interface RestoCardConfirmationViewController : UIViewController
#property(nonatomic) PFObject *commande;
#property(nonatomic) NSMutableArray *boxesCommande;
- (IBAction)confirmer:(id)sender;
#end
You should initialise the array before using it. Like this
- (void)awakeFromNib {
// Initialization code
_restoCardConfirmationVC = [[RestoCardConfirmationViewController alloc] init];
_restoCardConfirmationVC.boxesCommande = [NSMutableArray array];
}
Although this is a bad approach. You should initialise the array in the RestoCardConfirmationViewController initialisation.
You have not initialised the Array in which you are adding object. Allocate it either in awakeFromNib or in ViewDidLoad and then add an object in it.
Moreover, I don't find a good reason to alloc view controller in awakeFromNib of TableViewCell. You should allocate the VC only when Button is Tapped.
Hence the code should be like:
- (IBAction)select:(id)sender {
_restoCardConfirmationVC = [[RestoCardConfirmationViewController alloc] init];
[_restoCardConfirmationVC view]; //This will call the ViewDidLoad in Advance
[_restoCardConfirmationVC.boxesCommande addObject:_box];
self.select.enabled = NO;
}
And in ViewDidLoad of RestoCardConfirmationViewController:
- (void)viewDidLoad {
[super viewDidLoad];
_boxesCommande = [NSMutableArray array];
//Other initialisation code
}
I get the exc_bad_access error when running my project and trying to change the picker.
The error is occurring on
- (NSString*)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
Below is my code. From reading the other SO articles I realize I am probably not retaining my variable. I'm new and learning and appreciate the help.
#import <UIKit/UIKit.h>
#import "RootViewController.h"
#class RootViewController;
#interface AddConditionViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate> {
IBOutlet UITextField *txtConditionDetail;
IBOutlet UITextField *txtConditionArea;
IBOutlet UIPickerView *conditionNamesPicker;
NSMutableArray *names;
NSMutableArray *conditionDefs;
RootViewController *rvc;
NSString *conditionName;
}
#property (retain, nonatomic) IBOutlet UIPickerView *conditionNamesPicker;
#property (nonatomic,assign) RootViewController *rvc;
#property (nonatomic, retain) NSString *conditionName;
#property (nonatomic,assign) NSMutableArray *names;
#property (nonatomic,assign) NSMutableArray *conditionDefs;
#end
#import "AddConditionViewController.h"
#import "ConditionsAppDelegate.h"
#import "Condition.h"
#import "ConditionDef.h"
#import "Formula.h"
#implementation AddConditionViewController
#synthesize rvc, conditionNamesPicker, names, conditionDefs, conditionName;
/*
// Implement loadView to create a view hierarchy programmatically.
- (void)loadView {
}
*/
// Implement viewDidLoad to do additional setup after loading the view.
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Add Condition";
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:#selector(cancel_Clicked:)] autorelease];
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self action:#selector(save_Clicked:)] autorelease];
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
ConditionsAppDelegate *appDelegate = (ConditionsAppDelegate *)[[UIApplication sharedApplication] delegate];
conditionDefs = appDelegate.getConditionDefs;
self.names = [NSMutableArray arrayWithCapacity:[conditionDefs count]];
for (ConditionDef *def in conditionDefs) {
NSString *condition_name = def.condition_name;
if (!condition_name) {
condition_name = #"<Unknown Account>";
}
[names addObject:condition_name];
}
self.conditionNamesPicker.dataSource = self;
self.conditionNamesPicker.delegate = self;
NSLog(#"LINE 48");
}
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//Set the textboxes to empty string.
txtConditionArea.text = #"";
txtConditionDetail.text = #"";
//Make the Category name textfield to be the first responder.
[txtConditionArea becomeFirstResponder];
NSLog(#"LINE 63");
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
// The number of columns of data
- (int)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
// The number of rows of data
- (int)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
NSLog(#" LINE 87 - COUNT OF CONDITION DEFS TO SHOW = %i", names.count);
[conditionNamesPicker setDataSource:self];
return [names count];
}
// The data to return for the row and component (column) that's being passed in
- (NSString*)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
// NSLog(#"LINE 94 - here is the bug: conditionDefs[row] %#", names[row]);
return names[row];
}
// Catpure the picker view selection
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
// This method is triggered whenever the user makes a change to the picker selection.
// The parameter named row and component represents what was selected.
conditionName = names[row];
}
- (void) save_Clicked:(id)sender {
ConditionsAppDelegate *appDelegate = (ConditionsAppDelegate *)[[UIApplication sharedApplication] delegate];
//Create a Condition Object.
Condition *c = [[Condition alloc] init];
NSInteger newId = c.getNextConditionId;
Condition *cond = [[Condition alloc] initWithPrimaryKey:newId];
cond.condition_area = txtConditionArea.text;
cond.condition_detail = txtConditionDetail.text;
cond.condition_name = conditionName;
//Add the object
// [appDelegate addCondition:cond];
[appDelegate populateFromDatabase];
// ADD TO THE ARRAY:
// [cvc.categories addObject:cond];
// [cvc.Conditions addObject:cond];
rvc.Conditions = [appDelegate activeConditions];
// UPDATE THE TABLEVIEW
[rvc.tableView reloadData];
// release
[cond release];
[c release];
//Dismiss the controller.
[self.navigationController dismissViewControllerAnimated:YES completion: nil];
}
- (void) cancel_Clicked:(id)sender {
//Dismiss the controller.
[self.navigationController dismissViewControllerAnimated:YES completion: nil];
}
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
NSLog(#"LINE 159");
[theTextField resignFirstResponder];
return YES;
}
- (void)dealloc {
[txtConditionArea release];
[txtConditionDetail release];
[conditionNamesPicker release];
[super dealloc];
}
#end
Please change the property assign toretain for names property. And other array or those object inheriting fromNSObject. It is an object and you are keeping it as assign property. Use assign only for primitive data type. Try this and let me know.
You are setting the data source of PickerView in one the DataSource methods. This is not valid. Remove the below line
[conditionNamesPicker setDataSource:self];
from function:
numberOfRowsInComponent:
You are setting it again.
I am at loss as far as why there is a corruption in the below code. I pretty much lifted the existing "implementation" from examples. Still, when I try to change the value of my picker controller, code crashes because cloudProviders points to some random memory.
Please advise.
// SettingsViewController.h
#import <UIKit/UIKit.h>
#interface SettingsViewController : UIViewController
<UIPickerViewDelegate, UIPickerViewDataSource>
#property (retain, nonatomic) IBOutlet UIPickerView *picker;
#property (retain, nonatomic) NSArray *cloudProviders;
#end
// SettingsViewController.m
#import "SettingsViewController.h"
#interface SettingsViewController ()
#end
#implementation SettingsViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_cloudProviders = #[#"BOX", #"Yandex", #"Other"];
NSLog(#"Executing viewDidLoad");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc {
[_picker release];
[super dealloc];
}
#pragma mark -
#pragma mark PickerView DataSource
- (NSInteger)numberOfComponentsInPickerView:
(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component
{
return _cloudProviders.count;
}
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
return _cloudProviders[row];
}
#pragma mark -
#pragma mark PickerView Delegate
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row
inComponent:(NSInteger)component
{
NSLog(#"Executing didSelectRow");
}
/*
-(IBAction)textFieldReturn:(id)sender
{
[sender resignFirstResponder];
}
*/
#end
Also, what tools do people use to track down memory leaks and such on iOS? Is there something that could tell me who modified my pointer?
Thank you
Anna is correct.
Setting the property as self.cloudProviders solves the problem.