NSUserDefaults returns previous result - ios

I have a tableView where I can select a ship from a list, and when I tap it I want the information to pop up on another screen. The way I am currently doing this is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{
cargoShips* ship=[boatsForOwner objectAtIndex:indexPath.row];
UITableViewCell *cell = [self.boatsTableView cellForRowAtIndexPath:indexPath];
[self performSegueWithIdentifier:#"boatInfoSegue" sender:cell];
NSString *nameString = ship.name;
NSString *sizeString = ship.size;
NSUserDefaults *shipName = [NSUserDefaults standardUserDefaults];
[shipName setObject:nameString forKey:#"globalName"];
[shipName synchronize];
NSUserDefaults *shipSize = [NSUserDefaults standardUserDefaults];
[shipSize setObject:sizeString forKey:#"globalSize"];
[shipSize synchronize];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
And to load it back into text (in another file)
NSString *getName = [[NSUserDefaults standardUserDefaults]
objectForKey:#"globalName"];
NSString *getSize = [[NSUserDefaults standardUserDefaults]
objectForKey:#"globalSize"];
shipNameText.text = getName;
shipSizeText.text = getSize;
Now , this works great, except for the fact that it does not return the cell I selected to get to the infoView, but the previous selected object. So if I select the first object on the list, it returns null, the next item i select gets the result I should have had for the first object and so on.
What did I do wrong and how can I fix it?

NSUserDefaults is tool for saving settings, not for transferring object.
If I were you I made it this way:
#pragma mark - Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue
sender:(id)sender {
if ([segue.identifier isEqualToString:#"boatInfoSegue"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
CargoShip *ship = boatsForOwner[indexPath.row];
BoatViewController *vc = (BoatViewController *)segue.destinationViewController;
vc.ship = ship;
}
}
Class names should be capitalized, that's why I wrote CargoShip

From what I can see in your code. your problem is that you first perform the seque and then update the values in the NSUserDefaults move this line [self performSegueWithIdentifier:#"boatInfoSegue" sender:cell]; to the end of the method.
This should make it work, but you need to refactor you code.

Related

How to use NSUserDefault to send selected TableViewCell text to previous ViewController

I have a static UITableView with two prototype cells in my first UIViewController. in the first cell there is a label with "select your country". When user tap that cell, it goes to another UITableViewController that includes countries. When user select a country, in the first view label text should update with the selected country name. To do that I have to pass the selected data in second UIViewController to first view controller. I hope to use NSUserDefaults to do that. this is my second view controller with a tableview.
#implementation FlightfromTableViewController
{
NSArray *detailFlights;
}
- (void)viewDidLoad {
[super viewDidLoad];
detailFlights = #[#"colombo1",#"colombo2",#"colombo3",#"colombo14",#"colombo15",#"colombo16",#"colombo17"];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [detailFlights count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"identi" forIndexPath:indexPath];
cell.textLabel.text = [detailFlights objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Pass *p = [Pass new];
p.selectedString = [tableView cellForRowAtIndexPath:indexPath].textLabel.text;
NSString *selecteOne = p.selectedString;
[[NSUserDefaults standardUserDefaults] setObject:selecteOne forKey:#"selectedplace"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I appreciate if you provide answer with understandable code, because I'm new to iOS.
NSUserDefaults should not be used for application state. It's for user preferences which should persist when the app closes.
The correct way is to pass your data directly between your viewcontrollers: https://stackoverflow.com/a/9736559/78496
As suggested by #chedabob, NSUserDefaults should not be used to maintain application state.
Instead, you can use Protocols to back propagate the selection in First View Controller.
In your case, just use
[[NSUserdefaults standardUserDefaults] objectForKey:#"selectedplace"];
in viewWillAppear of FirstViewController to update the string.
First of all - you don't need to much code in your didSelect method to get your selected string. Just use your array:
NSString *selectedText = [detailFlights objectAtIndex: indexPath.row]; // or detailFlights[indexPath.row]
And when you come back to your master (first) ViewController you need to update your TableView, because data has changed. So, add viewWillAppear (if you haven't one) method and refresh your table:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear: animated];
[self.tableView reloadData]; // put here name of your tableView's property
}
And then, in your cellForRow method:
...
if (indexPath.row == 0) { // in first row you store country
NSString *text = #"Select country"; // default text
NSString *selectedCountry = [[NSUserdefaults standardUserDefaults] objectForKey:#"selectedplace"];
if (selectedCountry) { // if it exist
text = selectedCountry;
}
cell.textLabel.text = text;
}
You can get value from NSUserDefault by using this code in your First View Controller.
NSString *selectedPlace = [[NSUserdefaults standardUserDefaults] objectForKey:#"selectedplace"];
You should use delegate pattern to inform the first view controller about selected country. For this you have to write protocol in second view controller.
#protocol SecondViewControllerDelegate
-(void)secondViewController:(UIViewController *)vc selectedCountry:(NSString *)country;
#end
then in
(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
delegate.secondViewController(self) selectedCountry:#"selectedCountry";
}
After that in first view controller you implement this menthod to update the value.

How to pass data values to other ViewController Objective-C using NSDictionary?

I'm following a tutorial from a book and everything went fine untill i had to recieve the data from the tableView, i must mention that i modified some of the basic tutorial to fit my needs as i work with JSON values comming from a API. It crashes when i reference the value using self and says that the variables is nil. must also mention that the label has been added as a reference outlet and the customClass also as been created and added referenced with the View. Aditional to this added properly Segue to the detailViewController
UserDetailViewController.h
#interface UserDetailViewController : UIViewController
#property (nonatomic, strong) NSString *labelName;
#property (nonatomic, strong) IBOutlet UILabel *detailLabelName;
#end
UserDetailViewController.m
This is the code that does the transition between Table and detailView but there are a few values that does not belong to the code i have such as recipeName and recipeNames as you can see below:
recipeName is on my code labelName
recipeNames is on my code a dictionary [dictionary objectForKey:#"name"]
and have no idea how to put this part together. :(
// Here is where I handles the Data Transfer
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"userDetailView"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeDetailViewController *destViewController = segue.destinationViewController;
destViewController.recipeName = [recipeNames objectAtIndex:indexPath.row];
}
}
According to my understanding, you want to set text for detailLbelName depending on labelName. And this value is coming from your parent view controller.
You must be doing something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UserDetailViewController *detailController = [[UserDetailViewController alloc]initWithNibName:#"UserDetailViewController" bundle:nil];
self.detailController.lableName = #"Your Text According to Cell"
[self.navigationController pushViewController:detailController animated:YES];
}
In your UserDetailViewController:
- (void)viewWillAppear
{
self.title = self.labelName;
[self.detailLabelName setText:self.labelName];
}
To receive the data from tableView need to handle tableView delegate did select method and passed all required data to detailLabelName then refresh the screen.
Move the assignment lines in viewDidLoad to viewWillAppear.
- (void)viewWillAppear
{
self.title = self.labelName;
_detailLabelName.text = _labelName; // this is the breakpoint
}
Then, hwever you are storing the string in the table view (i assume you mean the cells specifically) then you may assign the value extracted from the table view cell after creating the detail view controller but before it is pushed onto the navigation stack and crashes your app.
please try this
In
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
of your table view do this.
UserDetailViewController *detailsView = [[UserDetailViewController alloc] initWithNibName:"Your nib name" bundle:[NSBundle mainBundle]];
UITableViewCell *reqDcell = [tableView cellForRowAtIndexPath:indexPath];
detailsView.labelName = //Text from reqDcell goes here. In particular the recipe name
[self.navigationController pushViewController:tableViewControls animated:YES];
Hope this helps.
********** EDIT ************
Ok so inorder to pass values using a dictionary , you would need an array of dictionaries which hold your data.
In terms of the link you posted, i have modified it for your understanding to use dictionaries.
recipeNames = #[[NSDictionary dictionaryWithObject:#"Mushroom" forKey:#"Recipie Name"],
[NSDictionary dictionaryWithObject:#"Hamburger" forKey:#"Recipie Name"],
[NSDictionary dictionaryWithObject:#"Pasta" forKey:#"Recipie Name"],
[NSDictionary dictionaryWithObject:#"Pizza" forKey:#"Recipie Name"],
[NSDictionary dictionaryWithObject:#"Noodles" forKey:#"Recipie Name"]];
The dictionary here will hold the json data that you have.
in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
// Display recipe in the table cell
NSDictionary *dict = [recipeNames objectAtIndex:indexPath.row];
cell.nameLabel.text = [dict valueForKey:#"Recipie Name"];
and the prepareForSegue function.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeDetailViewController *destViewController = segue.destinationViewController;
NSDictionary *dict = [recipeNames objectAtIndex:indexPath.row];
destViewController.recipeName = [dict valueForKey:#"Recipie Name"];
}
}
I hope this is helpful

View Controllers giving an error when creating a segue

I have a navigation controller and the first VC modals into the second one fine. I pressed ctrl+button and dragged it over, all works fine.
I am doing a second segue from the first VC (again) and this time its another button, I am ctrl+button and dragging it to the new VC and I get an USELESS error in XCODE -
2014-03-04 11:57:21.340 OutTonight[3173:60b] -[SettingsViewController
setDealdetail:]: unrecognized selector sent to instance 0x16e686d0
2014-03-04 11:57:21.342 OutTonight[3173:60b] * Terminating app due
to uncaught exception 'NSInvalidArgumentException', reason:
'-[SettingsViewController setDealdetail:]: unrecognized selector sent
to instance 0x16e686d0'
* First throw call stack:
Here is my prepareforseguecode
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.tableview indexPathForSelectedRow];
DealViewController *detailView = (DealViewController *)segue.destinationViewController;
detailView.dealdetail = [self.allcontent objectAtIndex:indexPath.row];
detailView.dealpostcode = [self.allpostode objectAtIndex:indexPath.row];
detailView.dealvenuename = [self.allname objectAtIndex:indexPath.row];
detailView.dealaddress = [self.alladdress objectAtIndex:indexPath.row];
detailView.dealaddress2 = [self.alladdress2 objectAtIndex:indexPath.row];
detailView.deallat = [self.alllat objectAtIndex:indexPath.row];
detailView.deallng = [self.alllong objectAtIndex:indexPath.row];
detailView.userlatitude = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLatitude"];
detailView.userlongitude = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLongitude"];
}
Any ideas?
I assume you have done something in -prepareForSegue: for the original segue? In which case, you need to make sure you are checking which segue it is in -prepareForSegue:, and doing the correct thing for each one.
Edit:
To expand on my answer, I guess you are using segue.destinationViewController, and calling setDealdetail: on it. This probably worked fine for your initial segue, because the destinationViewController responded to that message, but, the destination for the new segue doesn't. You need to check which segue is being performed. Using [segue.identifier isEqualToString:MySegueIdentifierString];
Edit 2 (after posting code):
Ok, you need to check which segue is being performed in your -prepareForSegue:. Something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:SegueToDealViewControllerIdentifier]) {
NSIndexPath *indexPath = [self.tableview indexPathForSelectedRow];
DealViewController *detailView = (DealViewController *)segue.destinationViewController;
detailView.dealdetail = [self.allcontent objectAtIndex:indexPath.row];
detailView.dealpostcode = [self.allpostode objectAtIndex:indexPath.row];
detailView.dealvenuename = [self.allname objectAtIndex:indexPath.row];
detailView.dealaddress = [self.alladdress objectAtIndex:indexPath.row];
detailView.dealaddress2 = [self.alladdress2 objectAtIndex:indexPath.row];
detailView.deallat = [self.alllat objectAtIndex:indexPath.row];
detailView.deallng = [self.alllong objectAtIndex:indexPath.row];
detailView.userlatitude = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLatitude"];
detailView.userlongitude = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLongitude"];
}
}
Where SegueToDealViewControllerIdentifier is the segue identifier for the original segue.

ios:onclick tableviewcell if nsuserdefaults exists goto view controller else goto to another viewcontroller

Hi friends am new in iphone apps developing in my project, am using storyboards I have a task where I need to authenticate for loading viewController on clicking from tableViewCell. I have subclassed UITableViewCell and I created a segue from that cell to viewController.
Now the problem is i need to authenticate the controller while clicking cell. if the user has not logged in it should goto login controller, else it it should go to activity controller. I have saved user details in NSUserDefaults. but I don't know how to authenticate it in cellForRowAtIndexPathon UITableViewCell
here is the code for my configuring cell:
else if(indexPath.row == 4) {
static NSString *simpleTableIdentifier4 =#"MenuDetails4";
activismCell *cell4 = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier4 forIndexPath:indexPath];
cell4.imgactivism.image= [UIImage imageNamed:#"icon5.png"];
cell4.activism.text = localize(#"some.activism");
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"firstname"]!=NULL && [defaults objectForKey:#"lastname"]!=NULL) {
[self performSegueWithIdentifier:#"goto" id:indexpath];
}
else if ([defaults objectForKey:#"firstname"] ==NULL && [defaults objectForKey:#"lastname"]==NULL) {
[self performSegueWithIdentifier:#"login" id:indexpath];
}
return cell4;
On clicking that particular tableViewCell if user already logged in it should goto activity ViewController else it it should goto login view controller.
Please help me how to do it. Thanks in advance
You don't perform the segue in the method cellForRowAtIndexPath, you need to put this code in the method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"firstname"]!=NULL && [defaults objectForKey:#"lastname"]!=NULL){
[self performSegueWithIdentifier:#"goto" id:indexpath];
}
else if ([defaults objectForKey:#"firstname"] ==NULL && [defaults objectForKey:#"lastname"]==NULL) {
[self performSegueWithIdentifier:#"login" id:indexpath];
}
}
in this method you can check the nsuserdefaults and then perform the segue accordingly.
Hi if you want to move after selection a specific row.Then you need to implement this method of tableView.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//You can apply your logic of selected row.
ViewControllerName *VC=[self.storyboard instantiateViewControllerWithIdentifier:#"ViewControllerName"];
aboutUsVC.strQuote=[quoteArry objectAtIndex:[indexPath row]];
[self.navigationController pushViewController:VC animated:YES];
//This one for presenting the viewController modally
//[self presentViewController:VC animated:YES completion:nil];
}
Thanks

How to change the text of a cell in UITableView with data from a NSDictionary

I store the information of a user in a variable of type NSUserDefaults when the user clicks on the save button.
I would like the launch of the application, the settings can be saved in the corresponding cells filled. So here's what I did in the corresponding file in the viewDidLoad method.
- (void)viewDidLoad
{
// [super viewDidLoad];
// Do any additional setup after loading the view.
if (self.navigationPaneBarButtonItem)
[self.navigationBar.topItem setLeftBarButtonItem:self.navigationPaneBarButtonItem
animated:NO];
//Initialise IndexPath
NSIndexPath *indexPathBroker = [NSIndexPath indexPathForRow:0 inSection:0];
NSIndexPath *indexPathPort = [NSIndexPath indexPathForRow:1 inSection:0];
NSUserDefaults *defaultConf;
defaultConf=[NSUserDefaults standardUserDefaults];
NSString * broker =[defaultConf stringForKey:#"broker"];
NSString *port= [defaultConf stringForKey:#"port"];
NSLog(#"Brokerdidload: %# et Portdidload: %#",broker,port);
//Create strings and integer to store the text info
ConfigDetailEditTableCell *editCellBroker = (ConfigDetailEditTableCell *)[_tableView cellForRowAtIndexPath:indexPathBroker];
ConfigDetailEditTableCell *editCellPort = (ConfigDetailEditTableCell *)[_tableView cellForRowAtIndexPath:indexPathPort];
//set data
editCellPort.EditCellValue.text =port;
editCellBroker.EditCellValue.text=broker;
// [editCellBroker.EditCellValue setText:broker];
// [[editCellPort textLabel] setText:port];
// [[editCellBroker textLabel] setText:broker];
// [[editCellPort textLabel] setPlaceholder:port];
// [[editCellBroker textLabel] setPlaceholder:broker];
// editCellPort.EditCellValue.text =*/
NSLog(#"editCellPort.EditCellValue: %# et editCellBroker.EditCellValue: %#",editCellPort.EditCellValue.text,editCellBroker.EditCellValue.text);
}
Variables in the broker and port, I have information but when I try to update the cell it does not work. The last NSLog that I am Null references
How to remedy????
Thank you in advance
Instead of trying to set the value of cell from viewDidLoad you should do it in cellForRowAtIndexPath: dataSource method of tableView
- (void)viewDidLoad
{
// [super viewDidLoad];
// Do any additional setup after loading the view.
if (self.navigationPaneBarButtonItem)
[self.navigationBar.topItem setLeftBarButtonItem:self.navigationPaneBarButtonItem
//Rest are not needed
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Initialize cell
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
NSString * broker =[defaults stringForKey:#"broker"];
NSString *port= [defaults stringForKey:#"port"];
cell.EditCellValue.text = indexPath.row==0?broker:port;
return cell;
}
You can also use the free Sensible TableView framework to automatically fetch your data from NSUserDefaults and display it on a table view. It will also automatically save whatever data has been entered back to NSUserDefaults. Comes in very handy.

Resources