Reputation: 2139
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 [array writeToFile....], I found that writeToFile fails because the array contains custom objects of XYZ class.
The possible solution to this is to convert the objects to NSData. What are the different ways of achieving this?? I found that NSCoding is suitable but cant understand how to use it. Any help will be greatly appreciated.
Upvotes: 2
Views: 8231
Reputation: 112857
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];
Upvotes: 9
Reputation: 1686
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
Upvotes: 1
Reputation: 18477
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
Upvotes: 0
Reputation: 7136
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.
Upvotes: 9
Reputation: 19071
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.
Upvotes: 0