Question

I'm a newbie iOS developer. I wrote a small application that save an NSMutableArray array with my objects that derived from NSObject. Application do the save but the file isn't created in document directory and application can't read. this issue is both on the simulator and my iPhone 3gs 4.2.1

My NSMutableArray definition inside the appDelegate class:

@property (nonatomic,retain, readwrite) NSMutableArray *places;

My NSObject class:

 #import <Foundation/Foundation.h>


@interface Place : NSObject {
    NSString *name;
    NSString *location;
}

-(id) init:(NSString *)name: (NSString *)location;

@property (retain,nonatomic,readwrite) NSString *name;
@property (retain,nonatomic,readwrite) NSString *location;

@end

My StorageService library class:

 #import "StorageService.h"


@implementation StorageService

-(id) init {
    self = [super init];
    if (self != nil) {

    }
    return self;
}


-(void) saveArrayToFile:(NSString*) filename : (NSMutableArray *)arrayToSave{
    // get full path
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *fullPath = [paths objectAtIndex:0];
    fullPath = [fullPath stringByAppendingPathComponent:filename];  
    NSLog(@"Save in %@",fullPath);
    [arrayToSave writeToFile:fullPath atomically:YES];
}

-(NSMutableArray*) readArrayFromFile:(NSString *)filename {
    // get full path
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *fullPath = [paths objectAtIndex:0];
    fullPath = [fullPath stringByAppendingPathComponent:filename];

    if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]) {
        NSMutableArray *data = [[NSMutableArray alloc] initWithContentsOfFile:fullPath];
        if (data == nil) {
            data = [[NSMutableArray alloc] init];
        }
        NSLog(@"Read from %@",fullPath);
        return data;
    } else {
        NSMutableArray *data = [[NSMutableArray alloc] initWithContentsOfFile:fullPath];
        return data;
    }
}

-(void) dealloc {
    [super dealloc];
}

@end

and My functions in the appDelegate:

    -(void) saveApplicationData {
    [self.storageService saveArrayToFile : PLACES_FILE : self.places];
}

-(void) loadApplicationData {
    self.places = [self.storageService readArrayFromFile:PLACES_FILE];
}

Here is my class that holds constant to filename:

    #import <Foundation/Foundation.h>

extern NSString * const PLACES_FILE = @"Places.dat";

@interface ApplicationConstants : NSObject {

}

@end

So what is wrong?

Thank you guys.

Was it helpful?

Solution

What you want is to let Place conform to the NSCoding protocol, to allow for serialization to and from files (and in memory data if wanted)

Extend Place as (I have also changed the name of the init method as your name was against every naming practice iOS has):

@interface Place : NSObject <NSCoding> {
    NSString *name; 
    NSString *location; 
}

-(id)initWithName:(NSString *)name location:(NSString *)location;

@property (retain,nonatomic,readwrite) NSString *name; 
@property (retain,nonatomic,readwrite) NSString *location;

@end

Your implementation is quite simple but you also need to implement two methods defined by the NSCoding protocol:

@implementation Place

@synthesize name, location;

-(id)initWithName:(NSString *)aName location:(NSString *)aLocation {
    self = [super init];
    if (self) {
        self.name = aName;
        self.location = aLocation;
    }
    return self;
}

-(id)initWithWithCoder:(NSCoder)decoder {
    self = [super initWithCoder:decoder];
    if (self) {
       self.name = [decoder decodeObjectForKey:@"name"];
       self.location = [decoder decodeObjectForKey:@"location";
    }
    return self;
}

-(void)encodeWithCoder:(NSCoder*)encoder {
    [encoder encodeObject:self.name forKey:@"name"];
    [encoder encodeObject:self.location forKey:@"location"];
    [super encodeWithCoder:encoder];
}

@end

With this in place, saving the places array to disk is as easy as:

[NSKeyedArchiver archiveRootObject:places toFile:path];

And decoding just as easy:

places = [[KSKeyUnarchiver unarchiveObjectWithFile:path] retain];

OTHER TIPS

To use writeToFile objects in array need to be plist capable type (NSDate, NSDate, NSString, NSArray, NSDictionary)

Implement NSCoding on the objects in array and use NSKeyedArchiver to serialize/deserialize. write:

[NSKeyedArchiver archiveRootObject:myArray toFile:self.places];

read:

[NSKeyedUnarchiver unarchiveObjectWithFile:path];

More info can be found here:

Persisting Custom Objects

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top