Problem with NSUserDefaults and deallocated Instance - iphone

I'm having a problem with NSUserDefaults. I've followed the steps in the books as closely as I can for my app, but still get the same problem.
I am getting a
*** -[NSUserDefaults integerForKey:]: message sent to deallocated instance 0x3b375a0
error when I try and load in the settings. Here is the code that I have, it is in the App Delegate class.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
recordingController = [[RecordingTableViewController alloc] initWithStyle:UITableViewStylePlain];
[recordingController retain];
// Add the tab bar controller's current view as a subview of the window
[window addSubview:tabBarController.view];
[self loadSettings];
}
-(void)loadSettings
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSNumber loop = [defaults objectForKey:#"loop_preference"];
NSNumber play = [defaults objectForKey:#"play_me_preference"];
NSNumber volume = [defaults objectForKey:#"volume_preference"];
}
As you can see I am not trying to do anything with the values yet, but I get the error on the line reading in the loop preference. I also get it if I try and read an NSString.
Any suggestions would be greatly appreciated.
Thanks
Peter

Since NSNumber is an object, it seems likely to me that you want:
NSNumber *loop = [defaults objectForKey:#"loop_preference"];
NSNumber *play = [defaults objectForKey:#"play_me_preference"];
NSNumber *volume = [defaults objectForKey:#"volume_preference"];
(Add asterisks * after NSNumber and before the variable names.) Though this does not seem directly related to your error message, it's the only apparent quirk in your code.

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

Retrieval of NSArray from NSUserDefaults returns empty array

I am experiencing strange behaviour with NSUserDefaults. I am initially storing an array to the user defaults in my AppDelegate.m:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *weekdayIDs = [defaults objectForKey:#"weekdayIDs"];
if (weekdayIDs == nil) {
weekdayIDs = [NSArray arrayWithObjects:#"su", #"mo", #"tu", #"we", #"th", #"fr", #"sa", nil];
[defaults setObject:weekdayIDs forKey:#"weekdayIDs"];
}
[defaults synchronize];
Now in a different view controller ContentViewController.m, I want to retrieve the array:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *weekdayIDs = [defaults objectForKey:#"weekdayIDs"];
But I just get an array without objects, although its count == 7. I also used arrayForKey: but with the same result. I added a screenshot from my breakpoint.
I am regularly using NSUserDefaults, but currently I am bit stuck on this. It's probably a stupid mistake, anyone care to help?
Thank you so much!
-- Update:
I also figured it might be a problem with the init of the NSArray in the first place, but even replacing its objects with manually created NSString *dwid_su = [NSString stringWithString:#"su"]; didn't work.
Your code works perfectly.
Just, print the description of you array and you will see what you want.
Right click on weekdayIDs variable and select Print Description of weekdayIDs
or use through lldb debugger console po weekdayIDs
or NSLog(#"%#", weekdayIDs);
Here the results.

NSUserDefaults, saving data issue

So I have an app that lets you put in a title and an author on the front page, then you hit enter and it will go into the actual features of the app. I want to save the data with NSUserDefaults, so that when they click the enter button, it saves it *AND goes into the next view. I have it setup with the storybord already to go into the next view, but when I use this code:
-(IBAction)enter:(id)sender {
titleString = [[NSString alloc] initWithFormat:[title text]];
[title setText:titleString];
NSUserDefaults *titleDefault = [NSUserDefaults standardUserDefaults];
[titleDefault setObject:titleString forKey:#"stringkey"];
authorString = [[NSString alloc] initWithFormat:[author text]];
[title setText:authorString];
NSUserDefaults *authorDefault = [NSUserDefaults standardUserDefaults];
[authorDefault setObject:authorString forKey:#"stringkey2"];
}
It will always crash when you hit the button. I have all the NSStrings defined and such, so I don't see what the problem is. I also have it loading with:
title.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"stringkey"];
author.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"stringkey2"];
Under the viewdidload, so can I have some help as to why this wouldn't work?
Just to optimize your -enter:method:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:title.text forKey:#"stringkey"];
[defaults setObject:author.text forKey:#"stringkey2"];
[defaults synchronize]; // this will store them instantly!
For the crash: can you please provide us with the exact crash log? Maybe your Button is linked to an unknown selector...
First, there are a few questions about this: here, here. Try searching around first, and at least let people know why the duplicate questions you found didn't work for you.
Secondly, I think you might benefit from adding a synchronize. Use this:
titleString = [[NSString alloc] initWithFormat:[title text]];
[title setText:titleString];
NSUserDefaults *titleDefault = [NSUserDefaults standardUserDefaults];
[titleDefault setObject:titleString forKey:#"stringkey"];
[titleDefault synchronize];
authorString = [[NSString alloc] initWithFormat:[author text]];
[author setText:authorString];
NSUserDefaults *authorDefault = [NSUserDefaults standardUserDefaults];
[authorDefault setObject:authorString forKey:#"stringkey2"];
[authorDefault synchronize];
I also changed the [title setText:authorString]; line to [author setText:authorString];. I do, however, think it is a bit redundant the way you are allocating the NSStrings to the value of the text fields and then setting the text back to the value of the string you created. I don't get the need. Anyway, hope this helps.

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 doesn't save

i'm trying to save some informations in an iphone/ipad app.
The problem is that it works but if i close the app (with the home button on the simulator or closing with cmd+q) the informations become lost!
this is my code (and, if you see, i used "syncronize")
- (IBAction)choose1{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:#"choose1" forKey:#"choose"];
[defaults synchronize];
}
- (IBAction)choose2{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:#"choose2" forKey:#"choose"];
[defaults synchronize];
}
- (IBAction)openview{
NSString *var = [[NSUserDefaults standardUserDefaults] objectForKey:#"choose"];
if (var == #"choose1"){
[self pushViewController:view1 animated:YES];}
else if (var == #"choose2"){
[self pushViewController:view2 animated:YES];
}
}
I don't understand why :(
When comparing strings, you should use the isEqualToString method, ie:
if ([var isEqualToString:#"choose1"]){
Otherwise you are comparing actual objects rather than their contents.
I am not entirely sure, but maybe it is saving your defaults and the error is located somewhere else. I am thinking about your "openView" method:
- (IBAction)openview{
NSString *var = [[NSUserDefaults standardUserDefaults] objectForKey:#"choose"];
if (var == #"choose1"){
[self pushViewController:view1 animated:YES];}
/** you are comparing to "choose1" here as well. **/
else if (var == #"choose1"){
[self pushViewController:view2 animated:YES];
}
Another possibilty might be that you never call your choose1() or choose2() methods?
This would explain why the value is never changed.
Despite from these 2 possibilites I think there is no error in the code you use to change the UserDefaults.
Hope this helps.
Regards,
Gjallar
ah, i'm sorry: i'm italian so i used the word "choose" with the italian translation "scelta".
Here i translated in english and i wrote "choose1" but in my code i used "choose2" (or "scelta2" :P)
for the other possibility (that i've never called the function choose1() or choose2() )... no, i've called, of course!