Domanda

I am trying to create a mutable array with objects of a custom class called Dog and save it to a file in the iPhone documents directory to be later read out of the file and back into my application. I am trying to use NSArray's writeToFile:atomically: method to accomplish this, but when I test the results of this method, it always returns a value of NO, and the file is not created, and the array is not stored. I have a few questions about this. What file format should I save my array to? What does it mean to atomically write an array to a file? How do I read out the contents of the file once the array is stored there And most importantly, why is my array not being stored into a file at the specified path? Thank you in advance and here is the code that I am using within my app's viewDidLoad method:

NSString *documentsDir = [NSSearchPathForDirectoriesInDomains
                          (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0];
dogFilePath = [documentsDir stringByAppendingPathComponent:@"arrayDogsFile.plist"];
NSFileManager *fileManager = [[NSFileManager alloc] init];

NSLog(@"%@",dogFilePath);

Dog *dog1 = [[Dog alloc] init];
dog1.name = @"Dog1";
Dog *dog2 = [[Dog alloc] init];
dog2.name = @"Dog2";
Dog *dog3 = [[Dog alloc] init];
dog3.name = @"Dog3";

NSMutableArray *arrayDogs = [NSMutableArray array];
[arrayDogs addObject: dog1];
[arrayDogs addObject: dog2];
[arrayDogs addObject: dog3];

//Sorts the array in alphabetical order according to name – compareDogNames: is defined in the Dog class
arrayDogs = (NSMutableArray *)[arrayDogs sortedArrayUsingSelector:@selector(compareDogNames:)];


if ([arrayDogs writeToFile:dogFilePath atomically:YES])
    NSLog(@"Data writing successful");
else
    NSLog(@"Data writing unsuccessful");
È stato utile?

Soluzione

You can not save your array of objects because objects are not NSString, NSData, NSArray, or NSDictionary.You could rather use NSKeyArchiver and NSKeyUnArchiver
For example:
#import "Foundation/Foundation.h"

@interface Dog : NSObject {**NSCoding**}//your class must conform to NSCoding Protocol  
@property (retain) NSString *Name;  
@end

The implementation needs some additional code. We need to implement the NSCoding protocol, which means two additional methods. (initWithCoder: and encodeWithCoder:)
#import "Dog.h"

@implementation Dog 
@synthesize Name;  
-(id)initWithCoder:(NSCoder*)decoder{    
    if ((self = [super init])) {  
        Name = [decoder decodeObjectForKey:@"Name"];  
}  
    return self;  
}



-(void)encodeWithCoder:(NSCoder*)encoder{  
    [encoder encodeObject:Name forKey:@"Name"];  
} 

Once we implement the protocol, saving will look like this:
// Save method
// We initialise our object and set the values

Dog *dog1 = [[Dog alloc] init];  
dog1.Name= @"Dog1";  
Dog *dog2 = [[Dog alloc] init];  
dog2.Name= @"Dog2";  
Dog *dog3 = [[Dog alloc] init];  
dog3.Name= @"Dog3";    
NSMutableArray *arrayDogs = [NSMutableArray array];  
[arrayDogs addObject: dog1];  
[arrayDogs addObject: dog2];  
[arrayDogs addObject: dog3];  

//Sorts the array in alphabetical order according to name – compareDogNames: is defined in the Dog class

arrayDogs = (NSMutableArray *)[arrayDogs sortedArrayUsingSelector:@selector(compareDogNames:)];  

// Store the array

[NSKeyedArchiver archiveRootObject:arrayDogs toFile:dogFilePath];  

//load the array*

NSMutableArray* retreivedADogObjs = [NSKeyedUnarchiver unarchiveObjectWithFile:dogFilePath]; 
@end  

Hope it will help you
Happy to help.*

Altri suggerimenti

Look at NSKeyedArchiver & NSKeyedUnarchiver Specifically you want + archiveRootObject:toFile: to save the file and + unarchiveObjectWithFile: to extract it again.

You will need to implement the NSCoding protocol in your Dog class as well to make this work. You just need to use something like - encodeObject: forKey: and – decodeObjectForKey: for each of your properties. The docs for NSCoder will show you which method to use for which kinds of property types (for example with BOOLs you use - encodeBool: forKey:).

Industrial answer: There's a whole subject for this in the SDK called "Archiving and Serialization".

If you don't have time to learn, but your dog does: Teach your Dog two new tricks: 1. How to render myself as a dictionary of strings and ints and so on. 2. How to init myself from that same kind of dictionary. This is basically a ghetto version of the industrial answer.

// Dog.m
- (NSDictionary *)asDictionary {

    NSMutableDictionary *answer = [NSMutableDictionary dictionary];
    [answer setValue:self.name forKey:@"name"];
    [answer setValue:self.numberOfBones forKey:@"numberOfBones"];
    return [NSDictionary dictionaryWithDictionary:answer];
}

- (id)initWithDictionary:(NSDictionary *)dictionary {

    self = [super init];
    if (self) {
        self.name = [dictionary valueForKey:@"name"];
        self.numberOfBones = [dictionary valueForKey:@"numberOfBones"];
    }
    return self;
}

When writing:

[arrayDogs addObject: [dog1 asDictionary]];
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top