NSUrl is not stored as absolutestring in NSUserDefault - iphone

I am referring Previous Post for storing NSURL of iPod Library in NSUserDefault. But it is not stored in NSUserDefault after application is closed.
I am using other NSStrings to store in NSUserDefaults which is perfectly done, But when i store NSUrl as absolute string.. it does not stores the value.
What could be the reason??
EDIT
Following code i am using to save NSUserDefault Value:
currentItem = [collection.items objectAtIndex:songCount];
songURL = [currentItem valueForProperty:MPMediaItemPropertyAssetURL];
[[NSUserDefaults standardUserDefaults] setObject:[currentItem valueForProperty:MPMediaItemPropertyTitle] forKey:#"songTitle"];
[[NSUserDefaults standardUserDefaults] setObject:[songURL absoluteString] forKey:#"songURL"];
avPlayer = [[AVPlayer alloc] initWithURL:songURL];
NSLog(#"songTitle: %# songURL : %#",[[NSUserDefaults standardUserDefaults]objectForKey:#"songTitle"], songURL);
Following error comes when i try to save the NSURL:
2011-09-13 18:47:23.258 Tabata Timer[933:707] songURL : ipod-library://item/item.mp3?id=-3715406019015217536
2011-09-13 18:47:23.258 Tabata Timer[933:707] *** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value 'ipod-library://item/item.mp3?id=-3715406019015217536' of class 'NSURL'.
2011-09-13 18:47:23.260 Tabata Timer[933:707] songTitle : Ghajini
2011-09-13 18:47:24.860 Tabata Timer[933:707] *** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value 'ipod-library://item/item.mp3?id=-3715406019015217536' of class 'NSURL'.
2011-09-13 18:47:24.963 Tabata Timer[933:707] songURL : ipod-library://item/item.mp3?id=-3715406019015217536
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.5 (8L1)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).

If you want to store NSURL then why are you converting it into string and saving it as string. It will increase your work effort.
You can try this:
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
[defaults setURL:[NSURL URLWithString:#"http://www.google.com"] forKey:#"urlValue"];
[defaults synchronize];
NSURL *url=[defaults URLForKey:#"urlValue"];
NSLog(#"%#",url);

The only thing I can think of that would explain it is that the URL is at least partially randomly generated and thus fails to load after you app removes reference to it. What do you mean, "closed"? Backgrounded? Or really terminated?
It could also be that you should be saving it as a string:yourURLString forKey:#"URL" instead of an object. It could be confusing the app. Try NSLog to output the URL string and see what you get. Let me know what it is. That will clarify things.

your string should have property declared...then try to store it in NSUserDefaults

Related

NSdata length crash on device

While running this code:
NSData *archivedSavedData = [[NSData alloc] init];
archivedSavedData = [defaults objectForKey:#"listOfAccessNumbers"];
NSLog(#"archivedSavedData length is %d", [archivedSavedData length] );
I am getting this crash error (last line) only when running on a device that is connected:
[__NSCFArray length]: unrecognized selector sent to instance 0x2398a0
2012-03-13 20:25:33.088[7301:707] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray length]: unrecognized selector sent to instance 0x2398a0'
* First throw call stack:
(0x34dbc88f 0x361e3259 0x34dbfa9b 0x34dbe915 0x34d19650 0xccb1b 0x31e13e33 0x31e38629 0x31dfcd7d 0x31ebf4dd 0x31e0555d 0x31e05579 0x31e0540b 0x31e053e7 0xcfedf 0x31e12e53 0x31e0c985 0x31ddac6b 0x31dda70f 0x31dda0e3 0x3600f22b 0x34d90523 0x34d904c5 0x34d8f313 0x34d124a5 0x34d1236d 0x31e0ba13 0x31e08e7d 0xcfd39 0xcbe28)
terminate called throwing an exception
This doesn't happen when running on the simulator or directly on the device with a distribution profile (through testflight for example).
Does anyone know how such a behavior could happen only in this case?
Thanks.
UPDATE: when trying to replace length with count I get this complication error: "No visible #interface for 'NSData' declares the selector 'count'"
UPDATE2: I understand that it should be an NSArray rather than an NSData, but my problem is that I did store archived NSData cause my array consists of custom objects, so I had to archived this data into NSData format when saving in NSUserDefault. How else should I approach that otherwise?
Thats how I store the data:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
[defaults setObject:data forKey:#"listOfAccessNumbers"];
array is an array of custom objects of the form of:
#interface NumberDataObj : NSObject {
NSString *inputName;
NSString *inputNum;
}
The error message says:
-[__NSCFArray length]: unrecognized selector sent to instance
That means that archivedSavedData is an array and that it doesn't (obviously) respond to length so you should declare archivedSavedData as an array and use count instead.
NSArray *archivedSavedData = [defaults objectForKey:#"listOfAccessNumbers"];
NSLog(#"archivedSavedData length is %d", [archivedSavedData count]);
Now, as to why this doesn't happen when running on the simulator, my guess is that your test scenarios don't make this part of the code get called.
EDIT
If you want to retrieve the data as NSData then use the method dataForKey:
NSData *archivedSavedData = [defaults dataForKey:#"listOfAccessNumbers"];
NSLog(#"archivedSavedData length is %d", [archivedSavedData length]);
The documentation says for dataForKey:
Return Value
The data object associated with the specified key, or nil if the key does not exist or its value is not an NSData object.
and for arrayForkey:
Return Value
The array associated with the specified key, or nil if the key does not exist or its value is not an NSArray object.
So aways use the appropriate method when you know the type of the data to avoid problems like this.
You have two problems as the code is written:
1) You allocate a variable called archivedSavedData that you reassign on the following line without releasing. This is okay if you are working with ARC, but the first line would then be unnecessary.
2) The second problem is that the object corresponding to the key #"listOfAccessNumbers" stored in your defaults object is of type NSArray. NSArray responds to the selector count, not length. Maybe you should look more closely at this object and recode accordingly.
Hope this helps :)
It's because [defaults objectForKey:#"listOfAccessNumbers"] returns an NSArray, not an NSData object.

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.

what is the best way for saving username and High Score

In my app I need to save a double value (high score) and String (player name) what should i use to get this.
any idea will be great.
Thank you
If this is all you're saving then NSUserDefaults should be fine
// To store
[[NSUserDefaults standardUserDefaults] setObject:name forKey:#"name"];
[[NSUserDefaults standardUserDefaults] setDouble:score forKey:#"score"];
// To read back in
NSString *name = [[NSUserDefaults standardUserDefualts] objectForKey:#"name"];
double score = [[NSUserDefaults standardUserDefaults] doubleForKey:#"score"];
// Don't forget that your name is autoreleased - if you want to keep it, set it to a retained
// property or retain it yourself :)
As deanWombourne said, you can use NSUserDefaults to store these data but it isn't very secure. If you don't want to store this data "in the air", you can take a look to SFHFKeychainUtils by Buzz Andersen to store them in the iPhone Keychain.
First of all, copy SFHFKeychainUtils files to your project. Click on the SFHFKeychainUtils.m and click on Get Info. Go to Target tab and check if the box near your target is checked. If not, check it. Control-click on your Framework folder and select Add Existing Framework. Find Security.framework and add it to your project. Check also that this framework is added to your target by doing the same procedure done for SFHFKeychainUtils.m. Now open you implementation file on where you want to use this code and add on the top #import "SFHFKeychainUtils.h".
This is a little example on how to use this code:
// to store your data
NSError *error = nil;
[SFHFKeychainUtils storeUsername:kName andPassword:name forServiceName:kStoredName updateExisting:YES error:&error];
[SFHFKeychainUtils storeUsername:kScore andPassword:score forServiceName:kStoredScore updateExisting:YES error:&error];
// to get them back
NSString *name = [SFHFKeychainUtils getPasswordForUsername:kName andServiceName:kScoredName error:&error];
double score = [SFHFKeychainUtils getPasswordForUsername:kScore andServiceName:kScoredScore error:&error];
// kName, kScore, kStoredName, kStoredScore are defined key but you can use also strings with #"your string here".
// It is important that when you store and get back a value, username and serviceName must be the same.

how to store NSDictionary in NSUserdefaults and how can I retrieve from it

I am getting some info from web server like this.
970,
Aditya2,
B,
JNTU1,
"Ram#gamil.com"
I need to store these values and I need to retrieve it from there where I want.
I found NSDictionary is correct for this.
I need to save these values in NSDictionary.
How can I do this?
To store and then receive:
[[NSUserDefaults standardUserDefaults] setObject:myDictionary forKey:#"dictionaryKey"];
//...
NSDictionary * myDictionary = [[NSUserDefaults standardUserDefaults] dictionaryForKey:#"dictionaryKey"];
Here's a link to the NSUserDefaults Class Reference

How to make a dump of the current NSUserDefaults standardUserDefaults state to disk and read back in?

I want to have some way of backing up the user defaults to a property list or XML, or some other appropriate file format that can be transfered over the net. How could I get a backup of these so that I can send them to a webserver and retrieve them back to the device and read them in to the user defaults database?
You can get a JSON string of the user defaults like this :
// You will need this at the top of your file
#import "CJSONSerializer.h"
// Get a dictionary of the user defaults
NSDictionary *dict = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
// Convert them to JSON
NSString *json = [[CJSONSerializer serializer] serializeObject:dictionary];
and to read them back into the device you can just do the opposite :
// You will need this at the top of your file
#import "CJSONDeserializer.h"
// Get the data from the server and re-create the dictionary from it
NSData *jsonData = <YOUR DATA FROM THE SERVER>;
NSDictionary *dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:nil];
// Put each key into NSUserDefaults
for (id key in [dict allKeys]) {
id object = [dict objectforKey:key];
[NSUserDefaults standardUserDefaults] setObject:object forKey:key];
}
[[NSUserDefaults standardUserDefaults] synchronize];
Have a look at the TouchJSON project page for more details and the download link.
Hope that helps.
NB There's no error checking in the above code - you might run into problems if your JSON contains int / float / etc because setObject:forKey: will fail.
I'd suggest either XML or JSON. Both have pretty good frameworks that ease working with them (TouchXML and TouchJSON).