Opening app from last opened UIViewController - iphone

I need my app to remember which was the last UIViewController opened so when the app is loaded out of memory, I substitute a rootViewController property in the AppDelegate with one saved in NSUserDefaults:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window = window;
frontViewController = [[SGLoginScreenViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:frontViewController];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
What I want to do is to put some code in the ViewDidLoad method of each ViewController and remember its name in NSUserDefaults to later use it in didFinishLaunchingWithOptions, something like this:
[[NSUserDefaults standardUserDefaults] setObject:self forKey:#"currentViewController"];
[[NSUserDefaults standardUserDefaults] synchronize];
The problem is, however, that XCode is giving me this warning:
*** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<SGMainScreenFirstTimeViewController: 0x8e1fea0>' of class 'SGMainScreenFirstTimeViewController'. Note that dictionaries and arrays in property lists must also contain only property values.
Any ideas on how to implement this whole thing right? Thanks in advance

You can only save in user defaults objects that can conform to the Key-Value coding (NSString, NSnumber, etc). Converting class to string and recreating class knowing class name would be the way to go for what you wish to achieve.
This would be a good approach for saving in NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromClass([self class]); forKey:#"currentViewController"];
[[NSUserDefaults standardUserDefaults] synchronize];
And for loading back you recreate the class based on the saved string, as below:
NSString *savedClassName = [[NSUserDefaults standardUserDefaults] objectForKey:#"currentViewController"];
UIViewController *controller = [(UIViewController *)NSClassFromString(savedClassName) alloc] init];

NSUSerDefaults is basically to store default values... not big objects ( list of items that can be saved includes (NSString,NSData,NSDictionary,NSArray,NSNumber) ..keep that in mind next time.
better way to do the functionality.
[[NSUserDefaults standardUserDefaults] setObject:#"Second View" forKey:#"currentViewController"];
[[NSUserDefaults standardUserDefaults] synchronize];
and then on app Load
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"currentViewController"] isEqualToString:#"Second View"])
{
//your code/logic

According to the documentation:
The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects.
So you can save name of your view controller and restore it on start, knowing its name

First thing is you can't save mutable values in NSUserDefaults. just check the psudocode following :
[[NSUserDefaults standardUserDefaults] setObject:#"nibnameofcurrentViewController" forKey:#"currentViewController"];
[[NSUserDefaults standardUserDefaults] synchronize];
when your app launch again then do following:
UIViewController *controller=[[UIViewController alloc]initWithNibName:[[NSUserDefault standerdDefault]objectForkey:#"currentViewController"] bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:frontViewController];
self.window.rootViewController = navController;

Related

saving in NSUserDefaults

I'm having a problem on how/where I can save my NSUserDefaults for applicationDidEnterBackground and applicationWillTerminate, I need to save my NSArray count in NSUserDefaults from another UIViewController when user exits the app or enter background. But I don't know if I would save the right integer, because my NSArray count is being updated when I am deleting on it on UIView.
I cant save it on viewDidLoad and viewDidAppear. Hope someone would help. Thankyou.
If u need to save from another ViewController then its better u add NSMutableArray in appDelegate. Whenever you delete or add object then save the count of array as it will overwrite like this:
[[NSUserDefaults standardUserDefaults] setInteger:[yourArray count] forKey:#"Count"];
[[NSUserDefaults standardUserDefaults] synchronize];
Retrieve like this:
NSInteger count = [[NSUserDefaults standardUserDefaults] integerForKey:#"Count"];
EDIT : synchronize : Writes any modifications to the persistent domains to disk and updates all unmodified persistent domains to what is on disk.
Refer NSUserDefaults_Class as clearly states gets called perodically and we don't have to wait for their call
Create the required NSMutableArray in your appDelegate class i.e create a property of NSMutableArray iVar,then later you can update ,add ,delete contents from it in any of the classes.Thus you shall get the array count in the applicationDidEnterBackground and applicationWillTerminate notification functions in the appDelegate function itself and the array count should be accurate..
in yourAppDelegate.h
create ..
#interface yourAppDelegate : UIResponder <UIApplicationDelegate>{
NSMutableArray *myArray;
}
#property(nonatomic,strong)NSMutableArray *myArray; //replace strong by retain if ios <5
in yourAppDelegate.m
#synthesize myArray;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *
)launchOptions{
self.myArray = [NSMutableArray array];
}
further in your required functions in appDelegate.m file
- (void)applicationWillTerminate:(UIApplication *)application
{
[[NSUserDefaults standardDefaults]setValue:[NSNumber numberWithInt:[self.myArray count] forKey:#"myOwnKey"]];
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
in case if you want to add objects to this array in any other class just create a delegate of the yourAppDelegate .
Eg in viewDidLoad of class A,
-(void)viewDidLoad{ // assuming viewController A
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplicatio sharedApplication]delegate];
[appDelegate.myArray addObject:#"1232"];
}
You can use this code to save value to NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:yourArray forKey:#"YourKey"]
[defaults synchronize];
For details on using NSUserDefault check this
[[NSUserDefaults standardUserDefaults] setBool:<#(BOOL)#> forKey:<#(NSString *)#>], this Is for Boolean you an add setInt/setFloat/SetDouble etc and even ObjectiveC objects with setValue/setObject.
[[NSUserDefaults standardUserDefaults] setValue:<#(id)#> forKey:<#(NSString *)#>];
[[NSUserDefaults standardUserDefaults] setObject:<#(id)#> forKey:<#(NSString *)#>];
To retrieve the value you can use getters like boolForKey ([[NSUserDefaults standardUserDefaults] boolForKey:<#(NSString *)#>]) intForKey etc..
Use removeObjectForKey to remove objects.

How to save password in UserDefault using the NSUserDefault?

I want to save password when user select remember me checkbox. I have code like this:is this correct?
In Appdelegate.m
#property(strong,nonatomic)NSString *savedno;
in .m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
self.navcontrol =[[UINavigationController alloc]initWithRootViewController:self.viewController ];
self.window.rootViewController = self.navcontrol;
[self.window makeKeyAndVisible];
self.savedno=[[NSUserDefaults standardUserDefaults]objectForKey:#"pass"];
if(savedno==nil)
{
NSDictionary *saveDict=[NSDictionary dictionaryWithObject:savedno forKey:#"pass"];
[[NSUserDefaults standardUserDefaults]registerDefaults:saveDict];
}
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
NSUserDefaults *userdefault=[NSUserDefaults standardUserDefaults];
[userdefault setObject:savedno forKey:#"pass"];
}
//ViewDelegate.m file
//event of checkbox
-(IBAction)check:(id)sender
{
if (checkboxSelected == 0)
{
[checkboxButton setSelected:YES];
[checkboxButton setImage:[UIImage imageNamed:#"checkbox-checked.png"]forState:UIControlStateNormal];
// userdefault=[NSUserDefaults standardUserDefaults];
// [userdefault setObject:user.text forKey:#"user"];
// [userdefault setObject:pass.text forKey:#"pass"];
self.callno=pass.text;
pass.text=self.callno;
AppDelegate *appdelegate=[[UIApplication sharedApplication]delegate];
appdelegate.savedno=self.callno;
NSLog(#"Data saved");
checkboxSelected = 1;
}
else
{
[checkboxButton setSelected:NO];
[checkboxButton setImage:[UIImage imageNamed:#"checkbox.png"]forState:UIControlStateNormal];
user.text=#"";
pass.text=#"";
checkboxSelected = 0;
}
}
- (void)viewDidLoad
{
user.clearButtonMode=UITextFieldViewModeWhileEditing;
AppDelegate *appdel=[[UIApplication sharedApplication]delegate];
if([user.text isEqualToString:#"bhoomi"])
{
pass.text=appdel.savedno;
}
[super viewDidLoad];
checkboxSelected = 0;
// Do any additional setup after loading the view, typically from a nib.
}
`
Don't. NSUserDefaults isn't the place for confidential information like passwords. Instead, use the KeyChain.
You should use the keychain to store information like passwords.
Have a look at SFHFKeychainUtils, it will allow to easily use the keychain in your app. It provides two methods: storeUserName:andPassword: and getPasswordForUsername that will make it a snap, and secure!
To save to user defaults do the following
[[NSUserDefaults standardUserDefaults] setValue:#"YourPassword" forKey:#"passowrd"];
//then call
[[NSUserDefaults standardUserDefaults] synchronize];
To get it back
NSString *password = [[NSUserDefaults standardUserDefaults] valueForKey:#"password"];
after setting value to NSUserDefaults you have to synchronize once to get it saved. Use following statement to do so.
[[NSUserDefaults standardUserDefaults] synchronize];
Hope this helps.
EDIT:
It is wise to store credentials into keychain rather than NSUserDefaults.
Use this KeyChain Helper class for the same
use this code...
NSUserDefault *userDefault = [NSUserDefaults standardUserDefaults];
[userDefault setValue:pass_str forKey:#"pass"];
[userDefault synchronize];
may this will help you...

NSUserDefaults - storing basic settings

I have a flipView application. On the FlipView I keep settings for the MainView and would like to use NSUserDefaults to store 2 integers for the MainView. I will use those integers in the main application. Is there some basic code that can implement what I'm trying to do?
I'd like to store the information on the FlipView (if changed) and have a default setting when the program is first run in the MainView.
Also, will I need to release the NSUserDefaults object once I'm finished using it?
check out below code, I had wrapped and make easy for you,
you can use below codes by:
import "Settings.h" in any code where you want to use, (maybe AppDelegate.m) in your case. then
to set value, use
[Settings setSetting:#"AUTOLOGIN" value:#"1"];
[Settings setSetting:#"OTHERPROPERTY" value:#"100"];
and remember that, store pointer datatype only,
to get setting value:
[Settings getSetting:#"AUTOLOGIN"];
here below there are two files, Setting.h and Setting.m , make those
header file is :
#import <Foundation/Foundation.h>
#interface Settings : NSObject {
}
+(id) getSetting:(NSString *)key;
+(void) setSetting:(NSString *)key value:(id)v;
#end
- and implementation file is
#import "Settings.h"
#implementation GCCSettings
static NSMutableDictionary *settings = nil;
+(id) getSetting:(NSString *)key{
if(settings == nil){
settings = [[NSMutableDictionary alloc] initWithDictionary:
[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"settings"]
];
}
return [settings objectForKey:key];
}
+(void) setSetting:(NSString *)key value:(id)v{
[settings setValue:v forKey:key];
[[NSUserDefaults standardUserDefaults] setObject:settings forKey:#"settings"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
#end
and finally don't release any objects, which you had not allocated using(new, init, retain etc).
You can store the integer with
[[NSUserDefaults standardUserDefaults] setInteger:1 forKey:#"theKey"] and retrive it with [[NSUserDefaults standardUserDefautls] integerForKey:#"theKey"]. That's really all you need to handle an integer with user defaults.
You don't release the NSUserDefaults object. It's a singleton, so only one will be created for the life of your app. You also don't own it which means you wouldn't be releasing it.

moreNavigationController save settings

I have a tab bar in my application and it has a "More" tab because there are more than five tabs.
This "More" tab is generated automatically and therefore I thought that it would all work "out of the box" but when I tried going to the "Edit" menu, substitute an icon on the bar with one in the "More" view, it was not saved next time I launced the application.
How can I let the user save this setting?
As futureelite7 said, that is the way to go. If you need help, this is how we do it:
- (void) tabBarController:(UITabBarController *)tabBarCtroller
didEndCustomizingViewControllers:(NSArray *)viewControllers
changed:(BOOL)changed {
NSUInteger count = tabBarCtroller.viewControllers.count;
NSMutableArray *tabOrderArray = [[NSMutableArray alloc] initWithCapacity:count];
for (UIViewController *viewController in viewControllers) {
NSInteger tag = viewController.tabBarItem.tag;
[tabOrderArray addObject:[NSNumber numberWithInteger:tag]];
}
[[NSUserDefaults standardUserDefaults] setObject:tabOrderArray forKey:#"savedTabOrder"];
[[NSUserDefaults standardUserDefaults] synchronize];
[tabOrderArray release];
}
And in your applicationDidFinishLaunching
NSArray *initialViewControllers =
[NSArray arrayWithArray:self.tabBarController.viewControllers];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *tabBarOrder = [defaults arrayForKey:#"savedTabOrder"];
if (tabBarOrder) {
NSMutableArray *newViewControllers =
[NSMutableArray arrayWithCapacity:initialViewControllers.count];
for (NSNumber *tabBarNumber in tabBarOrder) {
NSUInteger tabBarIndex = [tabBarNumber unsignedIntegerValue];
[newViewControllers addObject:[initialViewControllers objectAtIndex:tabBarIndex]];
}
self.tabBarController.viewControllers = newViewControllers;
}
You need to roll your own solution. Use the UITabBarControllerDelegate's
tabBarController:willEndCustomizingViewControllers:changed:
to capture the time after the user finishes editing the icons. Then you can save the user's setting (e.g. assign a number for each tab, and save it into an array etc.) and load it the next time the program launches.
You may use
[NSUserDefaults standardUserDefaults];
for a quick way to save such settings.

NSUserDefaults problem

I have this in my app delegate applicationDidFinishLaunching method:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"AcceptTC"] == nil){
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#"NO" forKey:#"AcceptTC"];
[defaults registerDefaults:appDefaults];
}
and I have this in my RootViewController viewDidLoad method:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if(![defaults boolForKey:#"AcceptTC"]){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Notice" message:#"By using this application you agree to be bound by the Terms and Conditions as stated within this application." delegate:self cancelButtonTitle:#"No Deal" otherButtonTitles:#"I Understand",nil];
[alert show];
[alert release];
}
and my alert view delegate does this:
if(buttonIndex == 0){
exit(0);
}
else{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:#"YES" forKey:#"AcceptTC"];
}
However when I click "I understand" (button index 1) and then restart the application I still see the alert view! Even though I've definiely set the value to YES.
I have no idea how to change this. :( I only want it to show the first time a user starts the application - i don't want to keep showing it every time they want to use it.
Thanks
In my application I'm using NSUserDefaults with a bool, works fine.
When the first ViewController loads, it will do:
BOOL terms = [[NSUserDefaults standardUserDefaults] boolForKey:#"termsaccepted"];
if (!terms) {
[self presentModalViewController:disclaimerViewController animated:YES];
}
Within the disclaimer view, after the button has been tapped:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"termsaccepted"];
[[NSUserDefaults standardUserDefaults] synchronize];
I think you're missing the "synchronize" part. However I find using a bool more streamlined, too.
Maybe you need to call synchronize on the defaults to save the changes to disk?
Concering registerDefaults:
The contents of the registration domain are not written to disk; you need to call this method each time your application starts. You can place a plist file in the application's Resources directory and call registerDefaults: with the contents that you read in from that file.
// Load default defaults
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary \
dictionaryWithContentsOfFile:[[NSBundle mainBundle] \
pathForResource:#"Defaults" ofType:#"plist"]]];
Code taken from this SO answer.
Another blog article about NSDefaults:
http://retrodreamer.com/blog/2010/07/slight-change-of-plan/