saving NSMutuableArray to NSUserDefault gives warning - objective-c

I have NSMutuableArray of UIImages . when trying to save him to userDefaults, i get warning.
If its an array of strings, its working ok.
//save to memory
NSMutableArray *savedImages=[[NSMutableArray alloc]init];
for(int j=0;j<[selectedButtonsTags count];j++)
[savedImages addObject:[assets objectAtIndex:[[selectedButtonsTags objectAtIndex:j] intValue]]];
[memoryInstance setTempImagesToSend:savedImages]; //here save to NSUserDefault
[savedImages release];
warning :
[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value
Why the userdefault care what objects my array holds ??

From the docs for NSUserDefaults:
The NSUserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Booleans, and URLs. A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData. For more details, see Preferences and Settings Programming Guide.
You will notice that UIImage is not in the list. You must convert the UIImage to an NSData object first before you can store the image in NSUserDefaults.
However, you should not use NSUserDefaults to store lots of binary data. Instead, write the images to the filesystem. Store them in an appropriate folder within the app's sandbox. You can store the filenames in NSUserDefaults if needed.

Related

Occasional EXC_BAD_ACCESS on NSUserDefaults access or synchronize

In a tab-based app when I switch between some tabs, I sometimes get EXC_BAD_ACCESS. It's not every time but if you flick back and forward a few times it eventually happens.
Defined in the .h:
NSUserDefaults *theData;
I've got this in viewWillAppear and viewWillDisappear:
[theData synchronize];
The line at fault gets called in a function at the viewWillAppear stage:
NSMutableArray *thisArray = [theData objectForKey:#"FriendsArray"];
I'm using NSUserDefaults to store a few dictionaries of data. This is populated by server calls, but there's no need for an internal database due to it being refreshed often. I am open to other ways of storing this data if that would be better.
I have tried a number of things like casting it (NSMutableArray *)[theData objectForKey:#"FriendsArray"]; or using arrayForKey and a number of other things with no improvement.
Any help or tips would be greatly appreciated.
NSMutableArray *thisArray = [theData objectForKey:#"FriendsArray"]; // retain
The way you try to make an array mutable is wrong. Also written like that, as suggested in the comments, you should probably retain that array.
Try init/alloc a new mutable array with objects like this :
NSMutableArray *thisArray =
[[NSMutableArray alloc] initWithArray:[theData objectForKey:#"FriendsArray"]];
Another method, -(id)initWithArray:(NSArray *)array copyItems:(BOOL)flag;, allows you to make a copy of the original objects.
Values in NSUserDefaults can not be mutable. You are trying to cast an immutable object into a mutable one. Try casting it into an NSArray, then cast that back into a mutable array. Should fix your issue.
There's no real reason for using
NSUserDefaults *theData;
Instead use this to recover a mutable array from UserDefaults:
NSMutableArray *thisArray =
[[NSUserDefaults standardUserDefaults] objectForKey:#"FriendsArray"] mutableCopy];
This gives you a RETAINED mutable array.
Note also that you only need to use synchronize when saving to UserDefaults, not when reading. You should synchronize pretty much after every save since your app can crash or be shut down by the iOS without you having a chance to synchronize.

Storing custom objects to NSMutableArray, then storing this NSMutableArray to NSUserDefaults

I would like to store some custom objects in an NSMutableArray, then store this NSMutableArray to NSUserDefaults. The custom objects look like this:
#interface myCustomClass:NSObject
{
NSString *string1;
NSString *string2;
NSArray *array;
NSURL *URL;
}
#end
I've checked the development documentations and learned that NSUserDefaults only supports some types such as NSData, NSDate, NSString, NSArray, NSDictionary. I have searched the answer to my question for a while but haven't got a solution. Would anyone please let me know how could I save my custom objects listed above to NSMutableArray then store this array to NSUserDefaults, and how to retrieve this mutable array? Thanks a lot in advance.
Objects that can be cached using NSUserDefaults must be property lists. If you would really like to use NSUserDefaults to cache these, then you must first implement a method that return all attributes necessary to recreate your object. This would mean a property list representation of your object, such as an NSDictionary. Think in terms of serialization/deserialization. For your case you have to ensure that your NSArray ivar in turn contains property lists only. If you can recreate NSURL using an NSString only, then save the NSString instead. You see it is getting complicated!
A much simpler approach would be to implement the NSCoding protocol in your custom class and save/retrieve your object or NSArray of objects using NSKeyedArchiver and NSKeyedUnarchiver. To implement the NSCoding protocol, you must implement only two methods initWithCoder: and encodeWithCoder:

Save list of CGPoints using NSUserDefaults

I have a bunch of CGPoints from a CCTMXLayer I want to save to NSUserDefaults but cannot seem to figure out an elegant way of doing so.
Originally I was hoping to save an NSDictionary with an NSMutableSet for a value containing several NSValues (valueWithCGPoint). From what I can tell neither NSMutableSet or NSValue is supported by NSUserDefaults.
At this point I am considering saving the x&y values of the CGPoint as a string and just converting it back and forth as needed.
There exists a pair of functions NSStringFromCGPoint and CGPointFromString. You can use these to produce an array of strings representing the points for serialization, and then convert back when you're finished.
Box them in NSValue objects. Once they're in there, you can write the NSValues out to disk (since they conform to <NSCoding>) or put them in NSUserDefaults or whatever.

How to save an NSMutableArray containing NSMutableArrays of custom objects in NSUserDefaults

I was able to save an NSMutableArray of custom objects to NSUserDefaults by implementing NSCoding in the custom class. However, now I want to save an NSMutableArray of these arrays. The compiler complains when I try to do this. How can this be done?
I found out how to do it. Basically, your transform the array into a data object using NSKeyedArchiver, and that is what you save with NSUserDefaults. Then when you get the data object back, you use NSKeyedUnarchiver to turn it back into an array.

Do I need to use NSKeyedArchiver?

I have an object. It has only two NSStrings as properties.
I created an array to hold several of these objects.
Do I need to use NSKeyedArchiver to save this array to disk, or can I just use NSUserDefaults?
If your object is a custom class, you will need to use NSKeyedArchiver before you put the contents in NSUserDefaults. See here.
You can just use [[NSUserDefaults standardUserDefaults] setObject:myArray forKey:myKey]; for writing and [[NSUserDefaults standardUserDefaults] arrayForKey:myKey]; for reading (there is no setArray:forKey: as it's not needed).
Also, if you got an array that you don't want to store inside NSUserDefaults there's an easy possibility to write and read arrays: -[NSArray writeToFile:atomically:] and +[NSArray arrayWithContentsOfFile:]. There also the same methods for NSDictionary to easily read/write dictionaries. Of course you're always free to use NSKeyed(Un)Archiver as well.