Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save NSMutableArray to disk

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.

like image 777
TalkingCode Avatar asked May 04 '09 11:05

TalkingCode


3 Answers

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.

like image 59
Marc Charbonneau Avatar answered Nov 16 '22 21:11

Marc Charbonneau


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 Persons, 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.)

like image 4
Jeremy W. Sherman Avatar answered Nov 16 '22 20:11

Jeremy W. Sherman


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.

like image 1
user708586 Avatar answered Nov 16 '22 21:11

user708586