Random data loss (NSUserDefaults) when popToRootViewControllerAnimated - ios

From time to time, my app loses all data when using:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
*/
[tableView deselectRowAtIndexPath:indexPath animated:YES];
switch (indexPath.row)
{
case kLANG_HEBREW:
// Hebrew is the default
self.arrayOfLanguages = [NSMutableArray arrayWithObjects:#"he", #"en", nil];
break;
case kLANG_ENGLISH:
self.arrayOfLanShorts = [NSMutableArray arrayWithObjects:#"en", #"he", nil];
break;
case kLANG_RUSSIAN:
self.arrayOfLanShorts = [NSMutableArray arrayWithObjects:#"ru", #"en", nil];
break;
case kLANG_ARABIC:
self.arrayOfLanShorts = [NSMutableArray arrayWithObjects:#"ar", #"en", nil];
break;
}
[[NSUserDefaults standardUserDefaults] setObject:self.arrayOfLanShorts forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"come_from_change_lang"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self.navigationController popToRootViewControllerAnimated:YES];
}
Thats very strange since I don't clear data in my app.

My guess is that your switch statement isn't always setting self.arrayOfLanShorts and it is then nil. Then when you set that in our user defaults it nils out the stored value and it would appear you lost your data. I would put a check of an if statement that your array is not nil before adding it to the defaults and if it is trace down how it didn't hit your switch statement.

Related

How to launch a different viewController on the second launch

Here the code I have under the viewController.m
This code will run when a user selects a viewController
-(void)switchViews {
UIStoryboard *mainStory = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainStory instantiateViewControllerWithIdentifier:schoolName];
[self presentModalViewController:vc animated:YES];
NSUserDefaults *defaultViewController = [NSUserDefaults standardUserDefaults];
[defaultViewController setObject:nil forKey:#"save"];
[defaultViewController synchronize];
}
This code will run on the second time the app is launched
-(void)loadNewView {
UIStoryboard *mainStory = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
NSUserDefaults *newUserDefault = [NSUserDefaults standardUserDefaults];
NSString *newVC = [NSString stringWithFormat:#"save", schoolName];
UIViewController *newViewController = [mainStory instantiateViewControllerWithIdentifier:newVC];
[self presentModalViewController:newViewController animated:YES];
}
Keeping in mind that schoolNameis a string
How can I run [self loadNewView] under the viewDidLoad but running it on the second time the app is launched?
You should do something like
id value = [[NSUserDefaults standardUserDefaults] objectForKey:#"save"];
if (value) {
UIViewController *vc = [mainStory instantiateViewControllerWithIdentifier:value];
[self presentModalViewController:vc animated:YES];
} else {
// first time logic
}
in your AppDelegate or wherever you have your navigation logic. You should not have that logic in viewDidLoad.
-(void)viewDidLoad {
[super viewDidLoad];
NSString *launchCount = #"LaunchCount";
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSInteger count;
if([userDefaults objectForKey:launchCount]) {
count = [userDefaults integerForKey:launchCount];
}
else {
count = 0;
}
count++; //increment the launch count
[userDefaults setObject:[NSNumber numberWithInt:count] forKey:launchCount];
[userDefaults synchronize];
if([userDefaults integerForKey:launchCount] >= 2) {
// Do your thang
}
}
on ViewDidLoad function do something like this
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedFirst"])
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasLauncheFirst"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self switchViews];
}
else
{
[[NSUserDefaults standardUserDefaults] setBool:No forKey:#"HasLauncheFirst"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self loadNewView];
}

How to check whether user is old or new when the user logins using NSUserDefaults in iOS?

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"username"] == nil)
{
//Load Login View if no username is found
NSLog(#"No username found");
self.nameLoginView=[[NewLoginViewController alloc]initWithNibName:#"NewLoginViewController" bundle:nil];
[self.navigationController pushViewController:self.nameLoginView animated:YES];
}
else
{
NSString *savedUsername = [defaults stringForKey:#"username"];
NSLog(#"Username found: %#", savedUsername);
self.mainView = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
[self.navigationController pushViewController:self.mainView animated:YES];
}
I mean if he is logging for first time in our app he has to go to newLoginView Controller and if user is logging for second time he has to go to another view controller? i am doing this code in view controller itself?
Hope i am getting right your problem, you have problem to find that user is saved in your user Default or new user please have a look of below link:Click here to find solution
Hope this will be help full for you.
NSString *userName = [[NSString alloc] init];
NSString *userPass = [[NSString alloc] init];
userName = [[NSUserDefaults standardUserDefaults] objectForKey:#"username"];
userPass = [[NSUserDefaults standardUserDefaults] objectForKey:#"password"];
if([userName isEqualToString:name.text] && [userPass isEqualToString:passcode.text])
{
authgrantflag=1;
}
// Compare entered combo with configurator stored values ---Offline Authentication //
NSLog(#"Authentication flag=%d",authgrantflag);
if(authgrantflag==1)
{
// Local authentication successfull call home page//
NSLog(#"Local authentication success");
[pop1 dismissPopoverAnimated:YES];
HomeScreen *dcrmainpage=[[[HomeScreen alloc] initWithNibName:nil bundle:nil]autorelease];
[self presentViewController:dcrmainpage animated:YES completion:nil];
}
else
{
HomeScreen1 *dcrmainpage=[[[HomeScreen1 alloc] initWithNibName:nil bundle:nil]autorelease];
[self presentViewController:dcrmainpage animated:YES completion:nil];
}

Delete all user data in UIViewController's after logout

When I login to my app, my app does push the ViewController XYZMainViewController, XYZMainViewController viewWillAppear:animated call method that makes a request to my API to retrieve the authenticated user data, at this time I update the text of a label to show the user name. When I logout the app, it returns me to the login ViewController, when I do login again with another user, XYZMainViewController label text contains the name of the previous user, without updating the label text.
XYZMainViewController.m
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:NO];
[self homeProfile];
}
- (void)homeProfile
{
[NXOAuth2Request performMethod:#"GET"
onResource:[NSURL URLWithString:#"http://{url}/users/userinfo"]
usingParameters:nil
withAccount:[XYZCommonFunctions user]
sendProgressHandler:nil
responseHandler:^(NSURLResponse *response, NSData *responseData, NSError *error){
NSDictionary *parsedData = [[NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error] objectForKey:#"data"];
_user = [parsedData objectForKey:#"user"];
[self.label setText:[NSString stringWithFormat:#"Welcome %#!", [_user objectForKey:#"username"]]];
}];
}
- (IBAction)logout:(id)sender {
XYZAppDelegate* appDelegate = (XYZAppDelegate*)[[UIApplication sharedApplication] delegate];
[appDelegate logout];
}
XYZAppDelegate.m
- (void)login
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *identifier = [prefs stringForKey:#"accountidentifier"];
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
NSString *viewIdentifier = #"WelcomeView";
if(identifier != nil){
NXOAuth2Account *account = [[NXOAuth2AccountStore sharedStore] accountWithIdentifier:identifier];
if(account != nil) {
viewIdentifier = #"MainView";
}
UIViewController *controller = [mainStoryboard instantiateViewControllerWithIdentifier: viewIdentifier];
[navigationController pushViewController:controller animated:NO];
return;
}
}
- (void)logout
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs removeObjectForKey:#"accountidentifier"];
[prefs synchronize];
for (NXOAuth2Account *a in [[NXOAuth2AccountStore sharedStore] accounts] ){
[[NXOAuth2AccountStore sharedStore] removeAccount:a];
}
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
[navigationController popToRootViewControllerAnimated:YES];
}
I need to reinitialize all data in XYZMainViewController.
Thank you.
Look like problem is related to fetching JSON Object. It is possible that everytime you have send same user to fetch user data. You are not using NSUserdefault object to display name, you are using value, which is return by JSON Object. According to me cause of error is "withAccount:[XYZCommonFunctions user]" line.
I would like to suggest, instead of using
-(void)viewWillAppear:(BOOL)animated {
you can use
- (void)viewDidLoad
so that your login action performed only when your LoginController loads,instead when LoginController appear.
New viewwillAppear look as given below -
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:NO];
[self.label setText:#""];
}
and ViewDidLoad -
- (void)viewDidLoad
{
[super viewDidLoad];
[self homeProfile];
}
Also check your json response, whether you are getting response success or error.According to response need to handle.
Hope this helps.

Making a View for the first use of an app

I wish to make an app that, when the user opens it for the first time he selects his country from a picker in order to make his flag appear on the main screen. If the user closes the app and opens it again I want the app to start the menu screen with his flag on it directly.
I am using the following code now but it doesn't work at all. Every time the app is opened it takes him to the picker VIew (TappViewController)
- (void)viewDidLoad
{
[super viewDidLoad];
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"FirstLaunch"]) {
secViewController *menu = [[secViewController alloc] init];
[self presentViewController:menu animated:YES completion:^{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"FirstLaunch"];
[[NSUserDefaults standardUserDefaults] synchronize];}];
}
else{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"FirstLaunch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Change your code like this:
- (void)viewDidLoad
{
[super viewDidLoad];
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"isPickerOpened"]) {
secViewController *menu = [[secViewController alloc] init];
[self presentViewController:menu animated:YES completion:^{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"isPickerOpened"];
[[NSUserDefaults standardUserDefaults] synchronize];
}];
}
}

NSUserDefaults to add row in a UITableViewController

I am trying to use NSUserDefaults to store a UITextField text and to retrieve it in another controller after you press Done button while editing.
in the controller where the user put information i code this :
-(IBAction)confirmAction:(id)sender{
UIViewController *prevVC = [self.navigationController.viewControllers objectAtIndex:1];
[self.navigationController popToViewController:prevVC animated:YES];
NSUserDefaults *try = [NSUserDefaults standardUserDefaults];
[try setObject:self.nameTextField.text forKey:#"name"];
[try synchronize];
}
and in the other controller i use this :
-(void)doneAction:(id)sender{
[self.tableView setEditing:NO animated:NO];
self.navigationItem.leftBarButtonItem = nil;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(editButtonClicked:)];
NSUserDefaults *try = [NSUserDefaults standardUserDefaults];
[ingredients addObject:[try stringForKey:#"name"]];
}
why i can't see any results. nothing is added in the tableview. why? did i write something wrong?
The most likely reason why you do not see the changes is that the UITableView does not know that you have added a new item to the ingredients array. In MVC terms, your controller made changes to the model, but it did not notify the view of that change.
You need to call [self.tableView reloadData]; at the end of your doneAction: method:
-(void)doneAction:(id)sender {
[self.tableView setEditing:NO animated:NO];
self.navigationItem.leftBarButtonItem = nil;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(editButtonClicked:)];
NSUserDefaults *try = [NSUserDefaults standardUserDefaults];
[ingredients addObject:[try stringForKey:#"name"]];
[self.tableView reloadData];
}
You should add [self.tableView reloadData]; after [ingredients addObject:[try stringForKey:#"name"]];

Resources