I have a class called XYZ inheriting from NSObject and an array which contains objects of XYZ. I need to write this array to a plist file on to documents directory. After trying
Conforming your XYZ class to the NSCoding protocol is indeed very suitable for what you're trying to do. To do so, add the NSCoding protocol to your class's interface declaration:
@interface XYZ <NSCoding>
Then, you need implement encodeWithCoder: and initWithCoder: in your implementation. "Encode with coder" means "take your object's current state, and pack it into a generic object called an 'encoder'". "Init with coder" means "given an already-packed encoder object, configure yourself with the data packed into the encoder". In both of these methods, the 'encoder' will be an instance of NSCoder, which has a fairly simple interface for encoding ("packing") and decoding ("unpacking") basic types.
Here's a sample implementation:
@implementation XYZ
- (id)initWithCoder:(NSCoder*)encoder
{
self = [self init];
if (self)
{
self.myIntProperty = [encoder decodeIntForKey:@"myInt"];
}
return self;
}
– (void)encodeWithCoder:(NSCoder*)decoder
{
[decoder encodeInt:self.myIntProperty forKey:@"myInt"];
}
@end
There is a very good tutorial on the Ray Wenderlich's blog which explains how to work with the NSCoding.
Simply you just have to implement the *-(void)encodeWithCoder:(NSCoder )encode and *-(id)initWithCoder:(NSCoder )decoder methods in your object that respects the NSCoding protocol like that:
// Header
@interface AnObject: NSObject <NSCoding>
// Implementation
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:ivar1 forKey:@"ivar1"];
[encoder encodeFloat:ivar2 forKey:@"ivar2"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:coder];
ivar1 = [[coder decodeObjectForKey:@"ivar1"] retain];
ivar2 = [[coder decodeObjectForKey:@"ivar2"] retain];
return self;
}
You can also check the official documentation here.
You need to implement two methods: -initWithCoder:
and -encodeWithCoder:
. Read the NSCoding
docs; they’re pretty straight-forward methods. You basically want to encode/decode your instance variables with a key that corresponds to its name.
After implementing encodeWithCoder:
and initWithCoder:
for the custom class here is how to write and read:
Write:
NSError *error;
NSData* archiveData = [NSKeyedArchiver archivedDataWithRootObject:yourClassInstance];
[archiveData writeToFile:filePath options:NSDataWritingAtomic error:&error];
Read:
NSData *archiveData = [NSData dataWithContentsOfFile:filePath];
YourClass *yourClassInstance = (NSArray*)[NSKeyedUnarchiver unarchiveObjectWithData:archiveData];
It's pretty straight forward. For given class Foo
:
#import <Foundation/Foundation.h>
@interface Foo : NSObject <NSCoding> {
NSArray* bar_;
NSUInteger baz_;
}
@property (nonatomic, retain) NSArray *bar;
@property (nonatomic, assign) NSUInteger baz;
@end
All you have to do to conform to the NSCoding
protocol is to implement the initWithCoder:
and decodeWithCoder
messages:
#import "Foo.h"
@implementation Foo
@synthesize bar = bar_;
@synthesize baz = baz_;
#pragma mark - NSCoding
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.bar forKey:@"bar"];
[encoder encodeInteger:self.baz forKey:@"baz"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if ((self = [super init])) {
self.bar = [decoder decodeObjectForKey:@"bar"];
self.baz = [decoder decodeIntegerForKey:@"baz"];
}
return self;
}
- (void) dealloc {
[bar_ release];
[super dealloc];
}
@end