How do I call the delegate of the pickerview when viewDidAppear? - ios

I need the last selected row in my pickerview to be totally recalled when the view appears! I have this code in my viewDidAppear it animates to the last selected row but it doesn't really call the delegate and the NSLog in my rows won't print without touching my picker and reselect them.
How do I do that?
- (void)viewDidAppear:(BOOL)animated {
NSUserDefaults *pickerViewSelectionDefaults = [NSUserDefaults standardUserDefaults];
[tasbeehPicker selectRow:[pickerViewSelectionDefaults integerForKey:#"picker"]
inComponent:0 animated:YES];
[pickerViewSelectionDefaults synchronize];
[UIPicker reloadAllComponents];
NSLog(#"Last selcted row was %d ",[[NSUserDefaults standardUserDefaults] integerForKey:#"picker"]);
}

The delegate is not supposed to be called when you update the picker through code. The delegates are only called when the user interacts with the picker. If you need the same code called in both cases then do something like this:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[myPicker selectRow:4 inComponent:0 animated:animated];
[self handlePickerSelection:myPicker];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
[self handledPickerSelection:pickerView];
}
- (void)handlePickerSelection:(UIPickerView *)pickerView {
// process selection
}

You can get selected row from below method,
Add this code in viewDidAppear,
int index = [pickerViewObject selectedRowInComponent:0];
[pickerViewObject selectRow:index inComponent:0 animated:YES];
selectedRowInComponent will give you selected row number, and then you can use selectRow:Row_number inComponent:Component_number animated:YES to select any row, picker delegate method will not get called.
If you want to save selected row in NSUserDefaults than you can do in in viewWillDisappear,
int index = [pickerViewObject selectedRowInComponent:0];
now save this index value in NSUserDefaults.

Related

Picker saves random data to NSUserDefaults

I've been working on a new tips & tricks project for a game called Dofus. In the first view the user is asked to pick their class out of a picker. Then they go to a next view and pick their level and stuff like that. The problem with the picker however is that its getting the wrong class out of the picker.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return [self.classNames count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *_myClass = self.classNames[row];
[prefs setObject:_myClass forKey:#"class"];
return self.classNames[row];
}
In the ViewDidLoad i declared my classes:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background"]];
self.classNames = #[#"Cra", #"Ecaflip", #"Eliotrope", #"Eniripsa",
#"Enutrof", #"Feca", #"Foggernout", #"Iop", #"Masqueraider", #"Osamodas", #"Pandawa", #"Rogue", #"Sacrier", #"Sadida", #"Sram", #"Xelor"];
}
Then in the next view I get the information like this (different .m file):
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background"]];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// getting an NSString
NSString *myClass = [prefs stringForKey:#"class"];
_textLabel.text = [NSString stringWithFormat:#"So you are a %# huh? Pretty cool! Its a good class. Fill out the rest so we are ready to go!", myClass];
}
Anyone any idea's how this is happening? Thanks in advance!
You are setting your preferences on the Picker's datasource call for the row title, instead of the delegate call for when the row is selected. For every row that is loaded into the view, pickerView:titleForRow:forComponent: is called, at which point you set the class preference, however, this does not correspond to the row that is selected in the picker, it corresponds to the next row to be displayed.
Instead, respond to the
pickerView:didSelectRow:inComponent: method, and set your preference there (you will still need to respond to the other one to set the row titles, just don't set the preference).
- (NSString *)pickerView:(UIPickerView *)pickerView
didSelectRow:(NSInteger) row
inComponent:(NSInteger) component {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *_myClass = self.classNames[row];
[prefs setObject:_myClass forKey:#"class"];
}
If you want store the selected row by the user you should this method from UIPickerViewDelegate
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
Something like that would work:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *_myClass = self.classNames[row];
[prefs setObject:_myClass forKey:#"class"];
[prefs synchronize];
}
}
Take a look at these links to better understand how works UIPickerView :
http://nscookbook.com/2013/01/ios-programming-recipe-7-using-the-uipickerview/
http://www.techotopia.com/index.php/An_iOS_7_UIPickerView_Example
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPickerView_Class/index.html#//apple_ref/doc/uid/TP40006842-CH3-SW9

How do you save the value of a UIPickerView as a string?

I am trying to save the selection in a UIPickerView as a string, but I seem to be losing the value after I dismiss the view. How can I retain this value?
.m file
/*********************************/
#pragma mark -
#pragma mark PickerView DataSource
//Below are the functions for the UIPicker:
- (NSInteger)numberOfComponentsInPickerView:
(UIPickerView *)pickerView
{
return 1;
}
//count of categories array denotes how many elements the picker will have
- (NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component
{
return arrCategorySelection.count;
}
//return the corresponding caregory
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return arrCategorySelection[row];
}
/*********************************/
#pragma mark -
#pragma mark PickerView Delegate
//Delegate method for the category picker
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
//trying to save the value as a string
selectedCategory = [arrCategorySelection objectAtIndex:row];
}
.h
#property (nonatomic, retain) NSString *selectedCategory;
A property is tied directly to the controller that it is declared in. To use the property, you need to access it before the controller is dismissed, normally with a delegate call. Apple has lots of example code on how to do this. Below is a summary.
Let's say MasterView is presenting PickerView. Normally, you want to do this with a segue.
[self performSegueWithIdentifier:#"Present PickerView" sender:nil];
In PickerView.h you declare a protocol before the #interface portion:
#protocol PickerViewDelegate <NSObject>
-(void)itemSelected:(NSString*)item;
#end
Then in the #interface portion, you declare a delegate property
#property(weak)id<PickerViewDelegate> delegate;
In MasterView, you need to populate this delegate in your prepareForSegue method
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"Present PickerView"]) {
PickerView *controller = segue.destinationViewController;
controller.delegate = self;
}
}
You also need to implement the delegate method (remember, it is best practice for the MasterView to both present and dismiss PickerView)
-(void)itemSelected:(NSString*)item {
// do something with item
[self dismissViewControllerAnimated:YES completion:nil];
// depending on the presentation, you may need this instead
// [self.navigationController popViewControllerAnimated:YES];
}
Now in PickerView.m, establish some way for the user to say he is done with his selection, say a tap of the save button on the upper right that calls this method:
-(IBAction)saveButtonTapped:(id)sender {
if (self.delegate && [self.delegate respondsToSelector:#selector(itemSelected:)]) {
[self.delegate itemSelected:self.selectedCategory];
}

Getting row without selection from UIPickerView

I have a pickerview that loads from a core data fetch on the view controller did load method. Everything works great, however I'm finding that I'm passing null values quite often, and that I'm having to spin the picker back and forth and click several times to get the value to hold.
I also have a problem if the user doesn't manually pick something, I need it to pass the value that the picker is on. I have a datepicker on the same viewcontroller and it passes whatever date it is sitting on without any problems. I'm probably overlooking something..any help would be appreciated
# pragma mark PickerView Section
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1; // returns the number of columns to display.
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [profiles count]; // returns the number of rows
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
// Display the profiles we've fetched on the picker
Profiles *prof = [profiles objectAtIndex:row];
return prof.profilename;
}
//If the user chooses from the pickerview
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
selectedProfile = [[profiles objectAtIndex:row]valueForKey:#"profilename"];
}
# pragma mark Segue Section
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"resultsSegue"]) {
ResultsVC *result = segue.destinationViewController;
result.profileName = [NSString stringWithFormat:#"%#",selectedProfile];
NSDate *selectedDate = [datePicker date];
result.trialDate = selectedDate;
}
}
You need to initialize selectedProfile to the 1st value in the picker. Do this in viewDidLoad. This way if the user never explicitly picks a value, the selectedProfile will be set to the 1st value by default.

UIPickerView selectRow won't select last row during initialization

I have found similar questions here and here. I have tried the answers to these and other questions found on stackoverflow and Apple's developer forums, with no luck.
I created a fresh project to test this, and it works fine in that new project. I am iteratively removing differences between my new test project and the one exhibiting this issue. Any pointers would be most helpful.
I have a UIPickerView connected to my view controller. I want to initialize the UIPickerView to the last value selected by the user. However if this row is the last row in the picker, it shows the second-to-last row selected in the UI instead.
Meanwhile, logging shows the correct row index selected in the UIPickerView object instance.
Selecting any row besides the last row in the picker works fine.
I have tried calling the selectRow:inComponent:animated method from viewDidLoad, viewWillAppear, and viewDidAppear - none of these make any difference. I have also tried calling reloadAllComponents in various orders relative to row selection and data initialization - again, no difference.
Some code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSParameterAssert(self.pickerView);
// Set pickerView data
self.pickerOptions = #[#"zero", #"one", #"two", #"three", #"four"];
// Picker View config
self.pickerView.dataSource = self;
self.pickerView.delegate = self;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSInteger selectedIndex = ([self.pickerOptions count] -1);
NSLog(#"About to select row: %d", selectedIndex);
[self.pickerView selectRow:selectedIndex inComponent:0 animated:NO];
NSLog(#"Selected value is %d", [self.pickerView selectedRowInComponent:0]);
}
#pragma mark UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
NSInteger numRows = [self.pickerOptions count];
NSLog(#"numRows: %d", numRows);
return numRows;
}
#pragma mark UIPickerViewDelegate
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
NSString *rowTitle = [self.pickerOptions objectAtIndex:(NSUInteger)row];
return rowTitle;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSString *value = [self.pickerOptions objectAtIndex:(NSUInteger)row];
NSLog(#"User selected value: %#", value);
NSLog(#"index: %d", row);
}
Log output:
-[CCSelectorViewController viewDidAppear:] About to select row index: 4
-[CCSelectorViewController pickerView:numberOfRowsInComponent:] numRows: 5
-[CCSelectorViewController viewDidAppear:] Selected row index is 4
Here is the screenshot of the wrong row being selected:
http://imgur.com/FVvu9RA
This is using iOS6, XCode 4.6.1.
Any ideas?

UIPickerView select first row programmatically

There are a lot of questions like this, but I believe my case is unique.
I have a pickerview that pops up when a textbox is clicked inside. The user selects their location in the pickerview, and it's put into the textbox.
When opening the pickerview, the slider is on the first element, but if i click the done button to minimize the pickerview, that no element is selected (i.e. you must scroll down and back up to select the first element)
I've tried
[pickerView selectRow:0 inComponent:0 animated:YES];
and various combinations of it, but it only puts the slider on that element, again not actually selecting it.
Some answers said to apply the above code in the viewDidLoad() method, but unfortunately I'm pulling the location array in from a web service and cannot do that.
Ideally, I'd like to work as - the user clicks in the textbox, the pickerview pops up as normal, if at that point the done button is clicked, the first item is selected.
Thankyou in advance
Swift 3+
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == yourTextField{
self.yourPickerView.selectRow(0, inComponent: 0, animated: true)
self.pickerView(yourPickerView, didSelectRow: 0, inComponent: 0)
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
//Do all the stuff to populate the TextField
}
Here is something you can try :
Set a var in your #interface, something like NSString *selectedString;.
When you init your UIPickerView (in pickerView:titleForRow:forComponent:), when you set the title for the row 0, set selectedString with the same string as the title of the row #0. Then, in pickerView:didSelectRow:inComponent:, set selectedString with the appropiate string :
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
// Some stuff
// Assuming "yourDataArray" contains your strings
selectedString = [yourDataArray objectAtIndex:row];
}
Then, when you call the method triggered by the push of the "done" button, use selectedString to set the text.
Hope this works out for you !
I had a same problem. My solution was this:
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
// Only for the text field with the picker
if (textField == self.yourTextField)
{
// Select the first row programmatically
[self.categoriesPicker selectRow:0 inComponent:0 animated:YES];
// The delegate method isn't called if the row is selected programmatically
[self pickerView:self.categoriesPicker didSelectRow:0 inComponent:0];
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
//Do all the stuff to populate the TextField
}
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
// Only for the text field with the picker
if (textField == self.yourTextField && [textField length]!=0)
{
// Select the first row programmatically
[self.categoriesPicker selectRow:0 inComponent:0 animated:YES];
// The delegate method isn't called if the row is selected programmatically
[self pickerView:self.categoriesPicker didSelectRow:0 inComponent:0];
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
//Do all the stuff to populate the TextField
}
/Create a IBACTION for the textfield with event editing did begin and the function should check if field is empty like this/
-(IBAction)asignFirst:(UITextField *)sender{
if ([sender.text isEqualToString:#""])
{
[yourPicker selectRow:0 inComponent:0 animated:YES];
sender.text = self.pickerData[0];
}
}

Resources