Okay I have spent the last 2 days trying to sort this one out. I have a class thats controlling my property list, It is used as a singleton class so its only instantiated once and it has one other method in it that is used to save the values to the plist.
The plist works sweet no matter what you do up untill you remove the app from the multitasking bar (i.e. close the app completely) then all of the values in the plist are reset to null.. However the plist is not lost.
So I am thinking now maybe I am overwriting the values in my plist that I have made in the root document directory for read and write capability. I am hoping with my code example you guys might be able to spot my mistake… I’m not sure what else I need to add.. if you have any question that will help you help me answer this problem then please let me know.
any help would be hugely appreciated and my children’s children’s children will be in debuted to you.
#import "EnginePropertiesController.h"
static EnginePropertiesController *sharedMyManager = nil;
@implementation EnginePropertiesController
@synthesize pSignature;
@synthesize pVersion;
@synthesize rNumber;
@synthesize dVReturned;
@synthesize cacheValue;
@synthesize manu;
@synthesize mod;
@synthesize submod;
#pragma mark Singleton Methods
+ (id)sharedManager {
@synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"EngineProperties.plist"];
NSLog(@"myplist path read = %@", plistPath);
// check to see if Data.plist exists in documents
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
// if not in documents, get property list from main bundle
plistPath = [[NSBundle mainBundle] pathForResource:@"EngineProperties" ofType:@"plist"];
}
// read property list into memory as an NSData object
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSString *errorDesc = nil;
NSPropertyListFormat format;
// convert static property liost into dictionary object
NSDictionary *tempRoot = (NSMutableDictionary *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
manu = [cacheValue objectForKey:@"Manu"];
mod = [cacheValue objectForKey:@"Mod"];
submod = [cacheValue objectForKey:@"SubMod"];
if (tempRoot && [tempRoot count]){
// assign values
self.pVersion = [tempRoot objectForKey:@"PSignature"];
self.pVersion = [tempRoot objectForKey:@"PVersion"];
self.rNumber = [tempRoot objectForKey:@"RNumber"];
self.dVReturned = [tempRoot objectForKey:@"DVReturned"];
cacheValue = [tempRoot objectForKey:@"Cache Value"];
}
}
return self;
}
- (void) saveData:(NSString *)methodName pSignature:(NSString *)TemppSignature pVersion:(NSNumber *)TemppVersion rNumber:(NSNumber *)TemprNumber dVReturned:(NSNumber *)TempdvReturned cacheValue:(NSNumber *)cValue
{
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"EngineProperties.plist"];
// set the variables to the values in the text fields
self.pSignature = TemppSignature;
self.pVersion = TemppVersion;
self.rNumber = TemprNumber;
self.dVReturned = TempdVReturned;
//This checks with methodName I would like to save the value from
//The reason for this is there are 3 different cache values I get at seperate times to save This if statment just makes sure they are in the correct order.
if ([methodName isEqualToString:@"Getmanu"]) {
self.manu = cValue;
} else if ([methodName isEqualToString:@"GetMod"]) {
self.mod = cValue;
} else if ([methodName isEqualToString:@"GetSubMod"]) {
self.submod = cValue;
}
//Set up cacheValue Dictionary that will be added to the property list root dictionary
self.cacheValue = [NSDictionary dictionaryWithObjectsAndKeys:
manu, @"Manu",
mod, @"Mod",
subMod, @"SubMod", nil];
//Pass appropriate values into plist
NSDictionary *plistDict = [NSDictionary dictionaryWithObjectsAndKeys:
protocolSignature, @"Protocol Signature",
pVersion, @"Protocol Version",
rNumber, @"Request Number",
dVReturned, @"Data Version returned",
cacheValue, @"Cache Value", nil];
NSString *error = nil;
// create NSData from dictionary
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
// check is plistData exists
if(plistData) {
// write plistData to our Data.plist file
[plistData writeToFile:plistPath atomically:YES];
} else {
NSLog(@"Error in saveData: %@", error);
}
}
@end
The Problem: nil Values
Here’s a problem: pVersion is assigned twice, while pSignature remains
nil.This should probably be
This in turn leads to trouble at saving time:
This constructor doesn’t know how many arguments it has, it just keeps going until it hits
nil. IfpSignatureis nil, it will save an empty dictionary.The Fix: Robust NSDictionary Creation
While the immediate solution is to fix the
pSignaturereading, it’s always fragile to construct dictionaries usingdictionaryWithObjectsAndKeys:. It’s much better to store each object individually, usingsetObject:forKey. This throws an exception if the object is nil, so test before calling.The Alternative: NSCoding
Another option for storage is to serialize. See the Archives and Serializations Programming Guide. This has tradeoffs: while saving and loading is simpler when it works, the resulting files are less human-readable.
Debugging
Finally, three places to put log statements, breakpoints or dialog boxes that help in cases like this:
arrayWithObjects:anddictionaryWithObjectsAndKeys: