I have an NSMutableArray that holds objects of the type Person (NSString,NSString,int) I am looking for a easy way to save this array to disc and load it again later.
I read alot about serialization but I never have done that. Maybe it's not the easiest way for me after all.
The first step is to make your Person class implement the NSCoding protocol. The basic strategy is to implement two methods to serialize and un-serialize each of the object's instance variables that you want to persist between sessions.
#pragma mark NSCoding Protocol
- (void)encodeWithCoder:(NSCoder *)encoder;
{
[encoder encodeObject:[self foo] forKey:@"foo"];
[encoder encodeDouble:[self bar] forKey:@"bar"];
}
- (id)initWithCoder:(NSCoder *)decoder;
{
if ( ![super init] )
return nil;
[self setFoo:[decoder decodeObjectForKey:@"foo"]];
[self setBar:[decoder decodeDoubleForKey:@"bar"]];
return self;
}
To actually write the objects to disk, you could use NSArray's writeToFile:
method, or use the NSKeyedUnarchiver class if you want to be more explicit about how it's done. In both cases you can also put your array into another data structure (a dictionary for example) if you want to include other items (such as a file format number) in your data file.
Mr. Charbonneau has the right idea. An NSCoder
abstracts the specific serialization of your object, and lets you worry only about what needs to be serialized/deserialized. In -encodeWithCoder:
, you might want to
NSAssert1([encoder allowsKeyedCoding],
@"%@ does not support sequential archiving.",
[self className]);
as not all coders support keyed archiving.
In -initWithCoder
, you should be sending -initWithCoder:
– not simply -init
– to super
prior to initializing your object:
self = [super initWithCoder:decoder];
if (!self) return nil;
// now use the coder to initialize your state
Alternatively, since your object is basically a property list already, you can add something like -[Person plistRepresentation]
:
- (NSDictionary *)plistRepresentation
{
return [NSDictionary dictionaryWithObjectsAndKeys:
[self firstName], @"firstName",
[self lastName], @"lastName",
[NSNumber numberWithInteger:[self age]], @"age", nil];
}
Then, to serialize an array of Person
s, you can yourself transform the persons into their plistRepresentation
and then use -[NSArray writeToURL:atomically:]
. (You can of course also employ the methods of NSProperyListSerialization
directly.)
It wont work here in my code by using writeToFile:atomically:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *issueURLsPlist = [documentsDirectory stringByAppendingPathComponent:@"test.plist"];
MyClass * myObject = [[MyClass alloc] init];
NSMutableArray * array = [[NSMutableArray alloc] init];
[array addObject:myObject];
[array writeToFile:issueURLsPlist atomically:YES];
MyClass.h
#import <Foundation/Foundation.h>
@interface MyClass : NSObject <NSCoding>
{
}
@property (nonatomic,copy) NSString * foo;
@property (nonatomic) double bar;
@end
MyClass.m
#import "MyClass.h"
@implementation MyClass
- (id)init {
self = [super init];
if (self) {
self.foo = @"test";
self.bar = 0.4f;
}
return self;
}
#pragma mark NSCoding Protocol
- (void)encodeWithCoder:(NSCoder *)encoder;
{
[encoder encodeObject:[self foo] forKey:@"foo"];
[encoder encodeDouble:[self bar] forKey:@"bar"];
}
- (id)initWithCoder:(NSCoder *)decoder;
{
if ( ![super init] )
return nil;
[self setFoo:[decoder decodeObjectForKey:@"foo"]];
[self setBar:[decoder decodeDoubleForKey:@"bar"]];
return self;
}
@synthesize foo;
@synthesize bar;
@end
When I'm using an array with NSStrings then the method writeToFile:atomically: is working fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With