saving in NSUserDefaults - iphone

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.

Related

Saving data in app delegate

I have a couple of arrays i wish to save when the application terminates. I implemented this using NSUserDefaults within app delegate. Can anyone take a look at my code, and see whats wrong? It doesn't work whatsoever.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
workouts = [NSMutableArray arrayWithObjects:nil];
menu = [NSMutableArray arrayWithObjects:#"Home",nil];
workoutNames = [NSMutableArray arrayWithObjects:nil];
routinesMade = [NSMutableArray arrayWithObjects:nil];
test = [NSMutableArray arrayWithObjects:nil];
defaults = [NSUserDefaults standardUserDefaults];
self.workouts = [defaults objectForKey:#"workouts"];
self.menu = [defaults objectForKey:#"menu"];
self.workoutNames = [defaults objectForKey:#"workoutNames"];
self.routinesMade = [defaults objectForKey:#"routinesMade"];
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application
{
defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:workouts forKey:#"workouts"];
[defaults setObject:menu forKey:#"menu"];
[defaults setObject:workoutNames forKey:#"workoutNames"];
[defaults setObject:routinesMade forKey:#"routinesMade"];
[defaults synchronize];
}
Btw, i declared defaults in the header file. Thanks guys!
I think I know what the problem is. Your code is inside the applicationWillTerminate: method. Unless you explicitly set your application not to run in background (by setting the 'Application does not run in background' key), it is almost certain that this method will never be called because by the time it gets terminated by the system, it will already have been suspended.
In this case consider saving the information you need in the applicationDidEnterBackground: method.
Hope this helps!
workouts and self.workouts are one property am i correct?
so you create array
workouts = [NSMutableArray arrayWithObjects:nil];
then override it with null because [defaults objectForKey:#"workouts"] contains null

Opening app from last opened UIViewController

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;

Way to persist MPMediaItemCollection objects? (selected from iPod)

I am making an app in which the user can select a song in a settings tab and have this played in a different view on demand. I want it so that this item can be stored if the user is to shut the app and reopen it another time.
I have managed to allow the user to select and store a song in with:
-(IBAction)showMediaPicker:(id)sender{
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeAny];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = NO;
mediaPicker.prompt = #"Select Alarm Sound";
[self presentModalViewController:mediaPicker animated:YES];
}
- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) mediaItemCollection {
[self dismissModalViewControllerAnimated: YES];
settingsData.selectedSong = mediaItemCollection;//Object of type MPMediaItemCollection
but I want the user to have to do this every time they use the app.
I have tried using NSUserDefaults:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:settingsData.selectedSong forKey:#"alarmSoundKey"];
[defaults synchronize];
but get the error:
* -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '' of class 'MPMediaItemCollection'. Note that dictionaries and arrays in property lists must also contain only property values.
What are my options please? Not really sure how to tackle this one...
SOLUTION -
I can't answer my own questions yet so I'll put it up here:
I HAVE FOUND MY OWN SOLUTION TO THIS:
First convert/encode the MPMediaItemCollection to an NSData Object and slam store it using NSUserDefaults using:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:mediaItemCollection];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:data forKey:#"someKey"];
[defaults synchronize];
From there, you can decode and use anywhere else in your app....
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:#"someKey"];
MPMediaItemCollection *mediaItemCollection = [NSKeyedUnarchiver unarchiveObjectWithData:data]
Hope that is some help to someone. Spread the word, this hasn't been covered enough. Have literally been working on this problem for about 4 hours...
You can only store property list values in NSUserDefaults. Since MPMediaItemCollection conforms to NSCoding you could use an NSKeyedArchiver to store it instead.
http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSKeyedArchiver_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003672
You then use NSKeyedUnarchiver to read it back out of the file later.
You can also use the MPMediaItemPropertyPersistentID property. You can form a query to retrieve the item from the iPod library when your application next launches, and gracefully handle things like when the user decides to remove the song from their library.

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.

how can i store value in an NSArray using WritetoFile?

i wana store the index of seleted cell of table using NSArray, can u help me....
You can use user defaults or property list for this.
Example on user defaults. You have a controller class that has access to the index and will load it at startup and write it into plist whenever it's updated:
If you have some kind of controller class then you would put this code into + (void)initialize, it initialises the variable if it does not exists in plist:
+ (void)initialize
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults =
[NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:5]
forKey:#"MyFunnyIndex"];
[defaults registerDefaults:appDefaults];
}
In your -(void)awakeFromNib (I'm assuming you're using some kind of controller class) load your last stored value:
-(void)awakeFromNib
{
int index =
[[NSUserDefaults standardUserDefaults] integerForKey:#"MyFunnyIndex"];
[somethingThatNeedsIndex setIndex:index];
// ...
}
Somewhere where the index is updated (or where you want to write it to plist), let's call it - (void)updateInterface:
- (void)updateInterface
{
[[NSUserDefaults standardUserDefaults]
setObject:[NSNumber numberWithInteger:index]
forKey:#"MyFunnyIndex"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I don't know if I understand the question correctly, but it sounds like you could use a property list to store this information. Property lists are very easy to use and quite efficient with small amounts of data.
Read the "Property List Programming Guide" for further explanation. There is even a tutorial in there.