Do I need to use NSKeyedArchiver? - objective-c

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.

Related

saving NSMutuableArray to NSUserDefault gives warning

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.

NSArrayController + NSTableView : automatically save changes without Core Data

OK, so I'm implementing a classic scenario :
A NSPopupButton with some items in it
When the selected value changes, my itemsArray is updated
The itemsArray is linked to an NSArrayController
Each item in the itemsArray is an NSMutableDictionary (with keys : title,content)
An NSTableView displays the titles of the arrangedObjects (binding)
An NSTextView displays the content of the selected item.
Now, what I want is to automatically save any changes to the itemsArray (or itemsArray's item title/content), but without using Core Data (which I suspect might have been the best way to go about it).
I imagine it's quite a basic question this one, but honestly I've never really like Cocoa's auto-magical way of doing things... so, I need your help...
How should I go about that?
You can write an array to a file very easily:
[yourArray writeToURL:someFileURL atomically:YES];
This will work if all the contents of the array are property list objects (i.e. they are NSNumber, NSString, NSDictionary, NSArray or NSData objects). This is the case in your example.
You can then recreate the array using either the arrayWithContentsOfURL: or initWithContentsOfURL: methods when you load from disk.
If your model object is more complex than just an array, then you should make your model object conform to the NSCoding protocol. This means you need to implement the initWithCoder: and encodeWithCoder: methods. You can then use the NSKeyedArchiver and NSKeyedUnarchiver classes to convert your object to and from an NSData representation that you can write to disk.
You should read the Archives and Serialization Programming Guide for more detailed information.
Another solution might be to add a Shared User Defaults Controller and bind the Controller Content Array from the Array Controller to the Shared User Defaults Controller

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.

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.