0

How do I save/read an NSMutableArray filled with objects I made a class for?

This is what I have so far... (where 'ObjectA' represents my class, and 'objects' is an array containing many instances of 'ObjectA')

//Creating a file
    //1) Search for the app's documents directory
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    //2) Create the full file path by appending the desired file name
    NSString *documentFileName = [documentsDirectory stringByAppendingPathComponent:@"save.dat"];


    //Load the array
    objects = [[NSMutableArray alloc] initWithContentsOfFile: _documentFileName];
    if(objects == nil)
    {
        //Array file didn't exist... create a new one
        objects = [[NSMutableArray alloc]init];
        NSLog(@"Did not find saved list, Created new list.");
    }
    else
    {
        NSLog(@"Found saved list, Loading list.");
    }

This will load an array if it exists. It works if the array is filled with property type objects like NSNumbers, I tested that. If I fill it with my own objects, it crashes! This is the error: (where 'objectAInt' is a private int belonging to 'ObjectA')

-[__NSCFNumber objectAInt]: unrecognized selector sent to instance 0x15d417f02013-11-19 17:28:58.645 My Project[1791:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber objectAInt]: unrecognized selector sent to instance 0x15d417f0'

What do I need to do to make my class, 'ObjectA', work with the save/read process like it does with NSNumbers and other NS objects of type (id)?

Thank You!

P.S. My class implements and is NSCoding compliant. If more information is needed please don't hesitate to ask! :)

EDIT -- Here is my ObjectA (per request) (it is a subclass of NSObject)

//
//  ObjectA.m
//  My Project
//
//  Created by Will Battel on 8/8/13.
//
//

#import "ObjectA.h"

@implementation ObjectA
@synthesize objectAString, objectAString2, objectAString3, objectAInt;

-(id)initWithName:(NSString *)_objectAString{
    self = [super init];

    objectAString = _objectAString;
    objectAInt = 2;
    objectAString3 = @"$0.00";

    return self;
}

-(id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (self) {
        NSLog(@"Decoding");
        [self setObjectAString:[decoder decodeObjectForKey:@"objectAStringKey"]];
        [self setObjectAString2:[decoder decodeObjectForKey:@"objectAString2Key"]];
        [self setObjectAString3Price:[decoder decodeObjectForKey:@"objectAString3Key"]];
        [self setobjectAInt:[decoder decodeIntForKey:@"objectAIntKey"]];
    }
    return self;
}

-(void)encodeWithCoder:(NSCoder *)encoder {
    NSLog(@"Encoding");
    [encoder encodeObject:objectAString forKey:@"objectAStringKey"];
    [encoder encodeObject:objectAString2 forKey:@"objectAString2Key"];
    [encoder encodeObject:objectAString3 forKey:@"objectAString3Key"];
    [encoder encodeInt:objectAInt forKey:@"objectAIntKey"];
}

@end
4
  • you should show us the NSCoding relevant code. you say u implemented it. maybe it is faulty. Commented Nov 20, 2013 at 0:57
  • That is entirely possible, I will add it! Commented Nov 20, 2013 at 1:01
  • When i run this, the NSLog(@"Encoding") is triggered, but NSLog(@"Decoding") never goes. Commented Nov 20, 2013 at 1:14
  • By the way, this crashes when the view controller's viewDidLoad is called, and specifically when [self instancesFromArchive]. Commented Nov 20, 2013 at 1:33

2 Answers 2

1

Since the array contains NSCoding compliant objects, you can use the coding methods, like this...

- (NSMutableArray *)instancesFromArchive {

    // compute documentFileName using your original code

    if ([[NSFileManager defaultManager] fileExistsAtPath:documentFileName]) {
        return [NSKeyedUnarchiver unarchiveObjectWithFile:documentFileName];
    } else {
        return [NSMutableArray array];
    }
}

// archives my array of objects
- (BOOL)archiveInstances {

    // compute documentFileName using your original code

    return [NSKeyedArchiver archiveRootObject:self.objects toFile:documentFileName];
}
Sign up to request clarification or add additional context in comments.

10 Comments

On the line: "return [[self alloc] init];", what is self referring to? Since this is a method I put it in the implementation of the view controller that is in charge of the array. This of course throws an error since I don't to alloc the View Controller. Where does this method go? Thanks, I'm new to this!!! :)
That was my bad, copied code from an app that does something similar. See the answer now. Elsewhere, you can just say self.objects = [self instancesFromArchive];
Thanks for fixing that, it still isn't working but I think something I did is causing it, probably related to ObjectA's implementation of NSCoding.
Done. It's at the bottom of the question.
@WillB - those look okay, but with two points: if the superclass is coding compliant then you would call super initWithCoder, not init. The other thing that's not necessarily a problem, but common practice is to access the ivars directly, not with the setters, so something like _objectAString = [decoder ... But otherwise those look okay.
|
0

NSNumber class is NSCoding compliant. Are your own objects NSCoding compliant?

1 Comment

Yes they are NSCoding compliant.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.