Sharing a plist file using iCloud - persistence

I have a relativley simple app which persists data to a plist file located in the documents folder. The data loads into a UITableView at startup. The user can then edit, delete or add records and any changes get saved back to the plist file.
Now I would like to share this data (the plist file) across devices using iCloud. I have looked at the documentation and my understanding is that I need to create a UIDocument to "manage" the plist file.
I have looked at several iCloud tutorials however they all store a simple string within a property in the UIDocument class, not an entire file (like a plist).
How do I share my plist file (or any other file, for that matter) to iCloud using the UIDocument object?
Would I convert the plist file contents to NSData, then save that in a property in the UIDocument? Should I be using use NsFileWrapper instead?
I seem to be having a difficult time wrapping my head around the UIDocument/iCloud arrangement. I am probably making this more complicated then it really is.

Not sure if anybody still needs a solution for that but I found a nice way to get this to work.
Since UIDocument only accepts Data as NSData or NSFilewrapper, I first created a Category for the NSDictionary Class that returns a NSDictionary from NSData. Here's the two files for the Category:
NSDictionary+DictFromData.h:
#import <Foundation/Foundation.h>
#interface NSDictionary (DictFromData)
+ (id)dictionaryWithData:(NSData *)data;
- (id)initWithData:(NSData *)data;
#end
and the NSDictionary+DictFromData.m
#import "NSDictionary+DictFromData.h"
#implementation NSDictionary (DictFromData)
+ (id)dictionaryWithData:(NSData *)data {
return [[[NSDictionary alloc] initWithData:data] autorelease];
}
- (id)initWithData:(NSData *)data {
NSString *tmp = nil;
self = (NSDictionary *)[NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:NULL
errorDescription:&tmp];
NSAssert1(tmp == nil,#"Error in plist: %#",tmp);
return [self retain];
}
#end
(source)
If you now import this Category in your UIDocument Subclass, you can easily load and save your Plist File to your iCloud container.
To load your Plist from iCloud add this to your UIDocument subclass (The Property contents is an NSDictionary):
- (BOOL)loadFromContents:(id)contents
ofType:(NSString *)
typeName error:(NSError **)outError {
if ([contents length] > 0){
self.contents = [NSDictionary dictionaryWithData:contents];
} else {
self.contents = nil;
}
// call some Methods to handle the incoming NSDictionary
// maybe overwrite the old Plist file with the new NSDictionary
return YES;
}
For saving your Data back to the iCloud add this:
- (id)contentsForType:(NSString *)typeName error:(NSError **)outError {
NSData * plistData = [[[NSData alloc]initWithContentsOfFile:YOUR_PLIST_FILE]autorelease];
return plistData;
}
If you now call:
[myUIDocument updateChangeCount:UIDocumentChangeDone];
YOUR_PLIST_FILE is getting synchronized. Remember that it takes about 10-15sec for your iCloud Container to update.

To use a plist with UIDocument, you can subclass UIDocument and override the following 2 methods with self.myDictionary (your plist) declared as a NSMutableDictionary.
- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)outError
{
if ([contents length] > 0)
{
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)contents];
NSMutableDictionary *dataDictionary = [unarchiver decodeObjectForKey:#"data"];
self.myDictionary = dataDictionary;
[unarchiver finishDecoding];
[unarchiver release];
}
else
{
self.myDictionary = [NSMutableDictionary dictionary];
}
return YES;
}
- (id)contentsForType:(NSString *)typeName error:(NSError **)outError
{
NSMutableData *data = [[[NSMutableData alloc] init] autorelease];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
if( !self.myDictionary )
{
self.myDictionary = [NSMutableDictionary dictionary];
}
[archiver encodeObject:self.myDictionary forKey:#"data"];
[archiver finishEncoding];
[archiver release];
return data;
}

Related

Exc Bad Access while unarchiving data from iCloud using UIDocument

Hi i am using iCloud support for my application and using UIDocument for storage. I was able to save data to iCloud and fetch the same for first time. But when i deleted and reinstalled the app on device, the seems to crash with EXC BAD ACCESS while trying to unarchive data using NSKeyUnarchiver.
Code.
BuyerDocument.m // UIDocument Subclass
// Accessor for BuyerData
- (BuyerData *)data {
if (_data == nil) {
if (self.fileWrapper != nil) {
self.data = [self decodeObjectFromWrapperWithPreferredFilename:BUYER_FILENAME]; // BUYER_FILENAME = #"buyer.data"
} else {
self.data = [[BuyerData alloc] init];
}
}
return _data;
}
- (id)decodeObjectFromWrapperWithPreferredFilename:(NSString *)preferredFilename {
NSFileWrapper * fileWrapper = [self.fileWrapper.fileWrappers objectForKey:preferredFilename];
if (!fileWrapper) {
NSLog(#"Unexpected error: Couldn't find %# in file wrapper!", preferredFilename);
return nil;
}
if([fileWrapper isRegularFile]){
NSLog(#"is regular wrapper");
}
NSData * data = [fileWrapper regularFileContents];
NSLog(#"data %#",data); // This logs successfully
// NSLog(#"data bytes %#",[data bytes]) // This also causes app to crash.
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; // App will crash here
return [unarchiver decodeObjectForKey:#"data"];
}
Loading BuyerDocument here.
- (void)loadDocAtURL:(NSURL *)fileURL {
// Open doc so we can read metadata
BuyerDocument * doc = [[BuyerDocument alloc] initWithFileURL:fileURL];
[doc openWithCompletionHandler:^(BOOL success) {
.......
BuyerData * data = doc.data;
....
[doc closeWithCompletionHandler:^(BOOL success) {
.....
}];
}
BuyerData.m
#define kVersionKey #"Version"
#define kNameKey #"Name"
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeInt:1 forKey:kVersionKey];
[encoder encodeObject:self.name forKey:kNameKey];
}
- (id)initWithCoder:(NSCoder *)decoder {
[decoder decodeIntForKey:kVersionKey];
NSString *nameData = [decoder decodeObjectForKey:kNameKey];
// NSLog(#">>>>>>>>>>>>>>>>>>> %#",name); // This logs for first 2-3 files and then crash occurs
return [self initWithName:nameData];
}
As i said when i first added data everything ran fine, it was only after deleting and reinstalling that crash began to occur. Also first 3-4 names are fetched and displayed in tableview before this crash occurs.
Tried this but of no help
I am fairly new to UIDocument and NSCoding. So can't say much about them. But i guess some how the issue might be with linked to NSData getting lost or corrupted out there. Am i missing something basic and important here. What am i doing wrong?

Error Reading Copied NSMutableArray on iPhone SDK

In one of my methods, I fetched and parsed a JSON and placed it inside an NSArray called jsonArray in -(void)method1. I then copied the contents of that jsonArray to an NSMutableArray called copiedJsonArray to be used on other methods. Problem is, copiedJsonArray crashes whenever I log its contents in the console from the other methods -(void)method2 but it logs fine in -(void)method1.
How can I fix this?
In my header file:
#interface MainViewController : UIViewController
#property (nonatomic, retain) NSMutableArray *copiedJsonArray;
In my implementation file:
#synthesize copiedJsonArray;
- (void)viewDidLoad
{
[self method1];
}
- (void)method1
{
NSString *urlString = [NSString stringWithFormat:THE_URL];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:url];
NSString *jsonString = [[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] autorelease];
NSDictionary *jsonDictonary = [jsonString JSONValue];
NSArray *jsonArray = [jsonDictonary valueForKeyPath:#"QUERY.DATA"];
self.copiedJsonArray = [[NSMutableArray alloc] initWithArray:jsonArray copyItems:YES];
NSLog(#"Copied JSON Array in Method 1: %#", self.copiedJsonArray);
[self method2];
}
- (void)method2
{
NSLog(#"Copied JSON Array in Method 2: %#", self.copiedJsonArray);
}
I also tried doing this too but it does the same error:
copiedJsonArray = [jsonArray mutableCopy];
I also tried implementing NSCopy but fails too:
#interface MainViewController : UIViewController <NSCopying>
{
NSMutableArray *copiedJsonArray;
}
I'm doing this so that I can do a loop in my copiedJsonArray without fetching its contents from JSON again and again when the user taps on my UISegmentedControl.
If you call method2 before method1 it will crash as copiedJasonArray has not been created. You should not create instance variables inside methods (as you cannot know if they have been called). You should do it when you create your viewController, in viewDidLoad for example.
And use properties:
#interface
#property (retain) NSMutableArray* copiedJsonArray;
#end
then either
#synthesize copiedJsonArray = _copiedJsonArray
or leave that line it out (the compiler will put it in automatically in 4.5)
access as self.copiedJsonArray or _copiedJSONArray.
Outside of getters,setters,inits and deallocs, use the self. form, it's safer.
You could also create _copiedJsonArray lazily in the setter:
- (NSMutableArray*) copiedJsonArray
{
if (!_copiedJasonArray)
_copiedJsonArray = [NSMutableArray alloc] init;
return _copiedJasonArray;
}

NSData to NSArray error in iPhone

I am using NSURLConnection to fetch XML data from the server. I am parsing the data and showing it in a tableview. It all works as expected. Now, I would like to save downloaded data for an offline use. The idea was to take downloaded NSData, convert it to NSArray and store it either to NSUserDefaults or in a separate file. However, I am having problems converting NSData to NSArray.
I added the logic to (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data method. What I am trying to do is as follows:
NSError *error;
NSPropertyListFormat plistFormat;
id object = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:&plistFormat error:&error];
if (error != nil) {
NSLog(#"Error %#", [error localizedDescription]);
[error release];
}
if ([object isKindOfClass:[NSArray class]]) {
NSLog(#"IS Array");
NSArray *objectArray = object;
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:#"myKey"];
} else {
NSLog(#"Not an array");
}
In log I get as follows:
Error The operation couldn’t be completed. (Cocoa error 3840.)
Not an
array
If I remove error handling and leave just the line
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:data];
my application crashes with the following message: `
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '*** -[NSKeyedUnarchiver
initForReadingWithData:]: incomprehensible archive (0x3c, 0x3f, 0x78,
0x6d, 0x6c, 0x20, 0x76, 0x65)'
Why is this happening? What is Cocoa error 3840?
My object implements NSCoding protocol, and has methods encodeWithCoder and initWithCoder. Does every property of my object has to be encoded / decoded?
Edit: Here is my object:
Currency.h
#interface Currency : NSObject<NSCoding>{
CGFloat value;
NSString *code;
NSDate *date;
NSString *description;
NSString *imagePath;
}
#property (nonatomic, assign) CGFloat value;
#property (nonatomic, retain) NSString *code;
#property (nonatomic, retain) NSDate *date;
#property (nonatomic, retain) NSString *description;
#property (nonatomic, retain) NSString *imagePath;
Currency.m
#implementation Currency
#synthesize value;
#synthesize code;
#synthesize date;
#synthesize description;
#synthesize imagePath;
static NSString * const keyCode = #"code";
static NSString * const keyDescription = #"description";
static NSString * const keyValue = #"value";
- (void)dealloc {
[code release];
[date release];
[description release];
[imagePath release];
[super dealloc];
}
- (void)encodeWithCoder:(NSCoder *)coder
{
if ([coder allowsKeyedCoding]) {
[coder encodeObject:code forKey: keyCode];
[coder encodeObject:description forKey: keyDescription];
[coder encodeFloat:value forKey: keyValue];
}
}
}
- (id)initWithCoder:(NSCoder *) coder {
self = [[Currency alloc] init];
if (self != nil)
{
code = [[coder decodeObjectForKey:keyCode] retain];
description = [[coder decodeObjectForKey:keyDescription] retain];
value = [coder decodeFloatForKey:keyValue];
}
return self;
}
#end
Revised answer:
So, there's three different concepts here: Generic XML, propertyLists (in either binary or XML format), and an Archive. You parse XML with an NSXMLParser or other library to convert into Obj-C objects. You can save core Obj-C objects (NOT including your custom class Currency) into property lists and read them back. Or you can archive any object/object graph (using encoders) into an archive and read it back with NSKeyedUnarchiver.
Even though underneath they may share implementations, you can't mix them. For example, first you tried to read XML as a propertyList, and even though pLists are XML, your generic CurrencyData XML doesn't have the right format for a plist (e.g. no ). In addition, even if you were to write a plist out, you'd have to convert Currency to a NSDictionary in order to make it storable in a plist, which means you wouldn't need the encoders.
Then you tried to read XML with NSKeyedUnarchiver and got the message "incomprehensible archive". Also correct, as it wasn't created with NSKeyedArchive.
So you can't use the original stream and directly plist or unarchive into your objects. But to save the parsed XMLArray for offline use, you can either convert Currency into an NSDictionary and use property lists, or just leave it as it is and use NSKeyedArchive and Unarchive like this (which leverages the encoders/decoders you've provided):
//To save
NSData * data = [NSKeyedArchiver archivedDataWithRootObject:xmlArray];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"myKey"]; //or store in another file
//To later read
NSData * data2 = [[NSUserDefaults standardUserDefaults] valueForKey:#"myKey"];
NSArray * newXMLArray = [NSKeyedUnarchiver unarchiveObjectWithData:data2];
Hope that clears it up. Investigating it also cleared up my own understanding of when to use which technique.
//Original comment:
If you've already parsed the incoming data into a model for your tableView, why not serialize that copy of the data rather than the original stream?
Is there a reason why you don't just save the NSData object directly to a file with
data writeToFile:(NSString*)path atomically:(BOOL)flag
?
I don't think you get an error in your NSPropertyList call - the propertyListWithData function returns nil if an error occurred, and I suppose the error is valid only then. You probably should check on return value != nil, and then print the error. Error 3840 marks the beginning of the range of property list errors, that doesn't look like an error in itself.
The description of propertyListWithData also says that it returns a property list, not an array, so it's not surprising that isKindOfClass says it's not an array ... see here:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSPropertyListSerialization_Class/Reference/Reference.html

NDictionary getting autoreleased even after retain or copy

I am using following method to get back an NSDictionary object in ViewDidAppear. But when I attempt to access it in CellForRowAtIndexPath() it is always nil. I have tried adding an extra retain and copy to it, but it still gets released. I have been pulling my hair for 3 hours now. Any help would be appreciated.
Excerpt :
#property(nonatomic, retain) NSDictionary* userInfoObj;
- (void) viewDidAppear:(BOOL)animated
{
[super viewWillAppear:animated];
**//The object has data in it at this point**
self.UserInfoObj = [self getUserInfo];
}
- (NSDictionary*)getUserInfo
{
JsonHelper *helper=[[JsonHelper alloc] autorelease];
NSString* apiURL = [self.appDelegate urlGetUserInfo];
apiURL = [apiURL stringByReplacingOccurrencesOfString:#"{user_id}" withString:[UserSettings lastLoginUserId]];
return [helper getJsonDictionaryFromWebMethod:apiURL];
}
- (NSDictionary*)getJsonDictionaryFromWebMethod :(NSString*) url
{
.....
.....
....
// Get JSON as a NSString from NSData response
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
// parse the JSON response into an object
// Here we're using NSArray since we're parsing an array of JSON status objects
dict = [[parser objectWithString:json_string error:nil] retain];
return dict;
}
Try putting self.UserInfoObj = [self getUserInfo]; in the viewDidLoad delegate method instead.

iPhone Serialization problem

I need to save my own created class to file, I found on the internet, that good approach is to use NSKeyedArchiver and NSKeyedUnarchiver
My class definition looks like this:
#interface Game : NSObject <NSCoding> {
NSMutableString *strCompleteWord;
NSMutableString *strWordToGuess;
NSMutableArray *arGuessedLetters; //This array stores characters
NSMutableArray *arGuessedLettersPos; //This array stores CGRects
NSInteger iScore;
NSInteger iLives;
NSInteger iRocksFallen;
BOOL bGameCompleted;
BOOL bGameOver;
}
I've implemented methods initWithCoder: and encodeWithCoder: this way:
- (id)initWithCoder:(NSCoder *)coder
{
if([coder allowsKeyedCoding])
{
strCompleteWord = [[coder decodeObjectForKey:#"CompletedWord"] copy];
strWordToGuess = [[coder decodeObjectForKey:#"WordToGuess"] copy];
arGuessedLetters = [[coder decodeObjectForKey:#"GuessedLetters"] retain];
// arGuessedLettersPos = [[coder decodeObjectForKey:#"GuessedLettersPos"] retain];
iScore = [coder decodeIntegerForKey:#"Score"];
iLives = [coder decodeIntegerForKey:#"Lives"];
iRocksFallen = [coder decodeIntegerForKey:#"RocksFallen"];
bGameCompleted = [coder decodeBoolForKey:#"GameCompleted"];
bGameOver = [coder decodeBoolForKey:#"GameOver"];
}
else
{
strCompleteWord = [[coder decodeObject] retain];
strWordToGuess = [[coder decodeObject] retain];
arGuessedLetters = [[coder decodeObject] retain];
// arGuessedLettersPos = [[coder decodeObject] retain];
[coder decodeValueOfObjCType:#encode(NSInteger) at:&iScore];
[coder decodeValueOfObjCType:#encode(NSInteger) at:&iLives];
[coder decodeValueOfObjCType:#encode(NSInteger) at:&iRocksFallen];
[coder decodeValueOfObjCType:#encode(BOOL) at:&bGameCompleted];
[coder decodeValueOfObjCType:#encode(BOOL) at:&bGameOver];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
if([coder allowsKeyedCoding])
{
[coder encodeObject:strCompleteWord forKey:#"CompleteWord"];
[coder encodeObject:strWordToGuess forKey:#"WordToGuess"];
[coder encodeObject:arGuessedLetters forKey:#"GuessedLetters"];
//[coder encodeObject:arGuessedLettersPos forKey:#"GuessedLettersPos"];
[coder encodeInteger:iScore forKey:#"Score"];
[coder encodeInteger:iLives forKey:#"Lives"];
[coder encodeInteger:iRocksFallen forKey:#"RocksFallen"];
[coder encodeBool:bGameCompleted forKey:#"GameCompleted"];
[coder encodeBool:bGameOver forKey:#"GameOver"];
}
else
{
[coder encodeObject:strCompleteWord];
[coder encodeObject:strWordToGuess];
[coder encodeObject:arGuessedLetters];
//[coder encodeObject:arGuessedLettersPos];
[coder encodeValueOfObjCType:#encode(NSInteger) at:&iScore];
[coder encodeValueOfObjCType:#encode(NSInteger) at:&iLives];
[coder encodeValueOfObjCType:#encode(NSInteger) at:&iRocksFallen];
[coder encodeValueOfObjCType:#encode(BOOL) at:&bGameCompleted];
[coder encodeValueOfObjCType:#encode(BOOL) at:&bGameOver];
}
}
And I use these methods to archive and unarchive data:
[NSKeyedArchiver archiveRootObject:currentGame toFile:strPath];
Game *currentGame = [NSKeyedUnarchiver unarchiveObjectWithFile:strPath];
I have two problems.
1) As you can see, lines with arGuessedLettersPos is commented, it's because every time I try to encode this array, error comes up(this archiver cannot encode structs), and this array is used for storing CGRect structs.
I've seen solution on the internet. The thing is, that every CGRect in the array is converted to an NSString (using NSStringFromCGRect()) and then saved. Is it a good approach?
2)This is bigger problem for me. Even if I comment this line and then run the code successfully, then save(archive) the data and then try to load (unarchive) them, no data is loaded. There aren't any error but currentGame object does not have data that should be loaded.
Could you please give me some advice? This is first time I'm using archivers and unarchivers.
Thanks a lot for every reply.
The problem with loading and saving solved another way...
Instead of implementing - (id)initWithCoder:(NSCoder )coder and - (void)encodeWithCoder:(NSCoder)coder I used this solution:
NSMutableData *data = [NSMutableData alloc];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:self.strCompleteWord forKey:#"CompleteWord"];
[archiver encodeObject:self.strWordToGuess forKey:#"WordToGuess"];
[archiver encodeObject:self.arGuessedLetters forKey:#"GuessedLetters"];
//[coder encodeObject:self.arGuessedLettersPos forKey:#"GuessedLettersPos"];
[archiver encodeInteger:self.iScore forKey:#"Score"];
[archiver encodeInteger:self.iLives forKey:#"Lives"];
[archiver encodeInteger:self.iRocksFallen forKey:#"RocksFallen"];
[archiver encodeBool:self.bGameCompleted forKey:#"GameCompleted"];
[archiver encodeBool:self.bGameOver forKey:#"GameOver"];
[archiver finishEncoding];
[data writeToFile:strPath atomically:YES];
[data release];
and
NSMutableData *data = [[NSMutableData alloc] initWithContentsOfFile:strPath];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
self.strCompleteWord = [[unarchiver decodeObjectForKey:#"CompletedWord"] copy];
self.strWordToGuess = [[unarchiver decodeObjectForKey:#"WordToGuess"] copy];
self.arGuessedLetters = [[unarchiver decodeObjectForKey:#"GuessedLetters"] retain];
//self.arGuessedLettersPos = [[unarchiver decodeObjectForKey:#"GuessedLettersPos"] retain];
self.iScore = [unarchiver decodeIntegerForKey:#"Score"];
self.iLives = [unarchiver decodeIntegerForKey:#"Lives"];
self.iRocksFallen = [unarchiver decodeIntegerForKey:#"RocksFallen"];
self.bGameCompleted = [unarchiver decodeBoolForKey:#"GameCompleted"];
self.bGameOver = [unarchiver decodeBoolForKey:#"GameOver"];
[unarchiver finishDecoding];
[data release];
And this works totally fine :)
I might be missing it, but I don't see any obvious bugs in this code.
Here are some ideas that might help:
Add some NSLog statements, and watch the debug output (open with command-shift-R in xcode) to see if your encode/decode methods are actually being called.
Check that the archive file is saved: Running in the simulator, you can save to any local path you want, such as /tmp/my_archive_file. Try to save to that file, and see if (a) the file exists with the right timestamp, and (b) you print out the file, you can see some recognizable strings (like "RocksFallen") in amongst the binary gooblygoo.
I also don't think it's necessary to check for allowsKeyed(En)coding since you know that's always going to be true when you're explicitly using NSKeyed(Un)archiver to do your dirty work for you. So you can throw away the other half of your code.
About coding those arrays of CGRects: I don't think you can directly add structs to an NSMutableArray, right? So they must be some kind of object, which means you can add NSCoding support to that object. If it's not your own object, you can subclass it and add that protocol, or try adding it as a category.
Thanks for reply Tyler.
I looked in the saved file and there are recognizable strings like RocksFallen and so on, also there are some recognizable values that might be saved in string variables.. So this seems to be good.
I tried to put some NSLogs in the code and not everything seems to be good. So...
When I launch simulator for the first time, there's no archive file, yes it is obvious, because nothing is saved. Then I change something and exit the application. When the application is being terminated, data might be archived, everything's fine. NSLog statements are written in the console, file is on the disk. But what is strange is that when I launch the application then, decode method(initwithcoder) is not being called.. Don't know why. Then I exit the simulator and run the simulator again. When I run it again, decode method is being called at the launchtime. But only at the first launchtime after running simulator, when I then work with simulator like exit the app and run it again, initWithCoder method is not being called and that's very strange for me..
So there are problems unarchiving it i think.
The best way to archive structs (that are not holding any pointers) with would be to wrap the values in an NSData block.
here, i'm dumping a struct array to the archiver:
for (int i = 0; i < items; i++) {
NSString *keyValue = [NSString stringWithFormat:#"YourStruct%i", i ];
NSData *dataset = [NSData dataWithBytes:(void*)&activeprofile[i] length:(sizeof(profileset))];
[encoder encodeObject:dataset forKey:keyValue]; // makes a nice, solid data block
}
and reading the data back in:
for (int i = 0; i < items; i++) {
NSString *keyValue = [NSString stringWithFormat:#"YourStruct%i", i ];
NSData *dataset = [decoder decodeObjectForKey:keyValue];
[dataset getBytes:&activeprofile[i] length:sizeof(profileset)];
}
There you have it: easy as pie and extremely flexible with datatypes!
A similar method for non-keyed archiving can be found here: http://borkware.com/quickies/one?topic=NSCoder Though I suggest sticking with keyed archiving, as NSArchive is not supported on the iPhone and has been classified as legacy code.