views:

237

answers:

1

I have a class to help me store persistent data across sessions. The problem is I want to store a running sample of the property list or "plist" file in an NSMutableArray throughout the instance of the Persistance class so I can read and edit the values and write them back when I need to.

The problem is, as the methods are publicly defined I cannot seem to access the declared NSMutableDictionary without errors. The particular error I get on compilation is:

warning: 'Persistence' may not respond to '+saveData'

So it kind of renders my entire process unusable until I work out this problem.

Here is my full persistence class (please note, it's unfinished so it's just to show this problem):

Persistence.h

#import <UIKit/UIKit.h>

#define kSaveFilename @"saveData.plist"


@interface Persistence : NSObject {

    NSMutableDictionary *saveData;

}

@property (nonatomic, retain) NSMutableDictionary *saveData;

+ (NSString *)dataFilePath;

+ (NSDictionary *)getSaveWithCampaign:(NSUInteger)campaign andLevel:(NSUInteger)level;
+ (void)writeSaveWithCampaign:(NSUInteger)campaign andLevel:(NSUInteger)level withData:(NSDictionary *)saveData;
+ (NSString *)makeCampaign:(NSUInteger)campaign andLevelKey:(NSUInteger)level;

@end

Persistence.m

#import "Persistence.h"


@implementation Persistence
@synthesize saveData;

+ (NSString *)dataFilePath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];

    return [documentsDirectory stringByAppendingPathComponent:kSaveFilename];
}

+ (NSDictionary *)getSaveWithCampaign:(NSUInteger)campaign andLevel:(NSUInteger)level
{
    NSString *filePath = [self dataFilePath];

    if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
    {
        NSLog(@"File found");

        [[self saveData] setDictionary:[[NSDictionary alloc] initWithContentsOfFile:filePath]]; // This is where the warning "warning: 'Persistence' may not respond to '+saveData'" occurs



        NSString *campaignAndLevelKey = [self makeCampaign:campaign andLevelKey:level];

        NSDictionary *campaignAndLevelData = [[self saveData] objectForKey:campaignAndLevelKey];

        return campaignAndLevelData;
    }
    else
    {
        return nil;
    }

}

+ (void)writeSaveWithCampaign:(NSUInteger)campaign andLevel:(NSUInteger)level withData:(NSDictionary *)saveData
{
    NSString *campaignAndLevelKey = [self makeCampaign:campaign andLevelKey:level];
    NSDictionary *saveDataWithKey = [[NSDictionary alloc] initWithObjectsAndKeys:saveData, campaignAndLevelKey, nil];

    //[campaignAndLevelKey release];

    [saveDataWithKey writeToFile:[self dataFilePath] atomically:YES];
}

+ (NSString *)makeCampaign:(NSUInteger)campaign andLevelKey:(NSUInteger)level
{
    return [[NSString stringWithFormat:@"%d - ", campaign+1] stringByAppendingString:[NSString stringWithFormat:@"%d", level+1]];
}   

@end

I call this class like any other, by including the header file in my desired location:

@import "Persistence.h"

Then I call the function itself like so:

NSDictionary *tempSaveData = [[NSDictionary alloc] [Persistence getSaveWithCampaign:currentCampaign andLevel:currentLevel]];
+3  A: 

Your problem is that you are using class methods to attempt to access an instance variable.

If you want it to be a class variable, then declare it before @implementation in the .m file, and either create class accessor methods for it, or access it directly.

Alternatively, and this is probably better (although I can't easily explain why), make your class methods into instance methods and create a singleton of the class.

See here: http://stackoverflow.com/questions/145154/what-does-your-objective-c-singleton-look-like and here: http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html for disscusion on singletons.

Paul Lynch
I can't get what you're suggesting to work properly. I added the NSMutableDictionary about the @implementation and it always comes back blank.
meridimus
The line where you call it is invalid - if you alloc, you should call an init method.Then you don't say if you changed your code to access saveData directly; as you are trying to call instance methods on your class object, which won't work, as I think I said already. It is possible that you don't understand the difference between classes and instances?
Paul Lynch