Array of Arrays - writing to File problem - iphone

and again my array of arrays ... I try to improve my app performance by buffering arrays on file for later reuse.
I have an NSMutableArray that contains about 30 NSMutableArrays with NSNumber, NSDate and NSString Objects.
I try to write the file using this call:
bool result = [myArray writeToFile:[fileMethods
getFullPath:[NSString
stringWithFormat:#"iEts%#.arr",
[aDate shortDateString]]]
atomically:NO];
=> result = FALSE.
The Path method is:
+ (NSString *) getFullPath:(NSString *)forFileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:forFileName];
}
and the aDate call returns a shortDateString with ddMMyy.
The NSLog
NSLog(#"%#", [fileMethods getFullPath:[NSString stringWithFormat:#"iEts%#.arr",
[aDate shortDateString]]]);
on the path generation returns:
/Users/me/Library/Application Support/iPhone Simulator/User/Applications/86729620-EC1D-4C10-A799-0C638BB27933/Documents/iEts010510.arr
FURTHER:
It must have something to do with the
Array of Arrays, since I also write 3
further simple arrays (containing
NSStrings) that all succeed.
The Array of Arrays gets generated using the addObject method
Any ideas what could cause the trouble?

AFAIK the write to file uses object archiving hence some objects in your array of arrays can't be archived.

Have you got any NSNulls in your arrays anywhere? I don't think they count as plist objects and so would cause the write to fail.

Related

writing NSString type to a file

I'm implementing the following function on appdelegate,
but I need to write NSString type instead of typical float values.
Since xcode doesn't allow an object to be in my desired position,
I used char* instead as follows, where as my data to be passed are of type NSString.
As expected, it doesn't work...
How could I manipulate it so that I could write NSString data type?
Should I make some conversion?
Please help me out..
- (void)addHallOfFamer:(char*)newHofer{
[hofArray addObject:[NSString stringWithFormat:#"%#",newHofer]];
[hofArray sortUsingSelector:#selector(compare:)];
NSArray* paths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* hofArrayPath = [documentsDirectory
stringByAppendingPathComponent:#"hofers.plist"];
[hofArray writeToFile:hofArrayPath atomically:YES];
}
(added)
following is how I'm calling the written NSStrings from another view, which doesn't reflect my updating.
MainAppDelegate* delegate;
delegate = (MainAppDelegate*)[[UIApplication sharedApplication] delegate];
NSArray *hofers = [[delegate.hofArray reverseObjectEnumerator] allObjects];
hoferName1.text = [NSString stringWithFormat:#"%#",[hofers objectAtIndex:0]];
First, with the current char * argument, you need to use %s as your format directive, not %#.
Second, to use an NSString * as your argument, just add it to hofArray.
The easiest solution would be to just save the array in NSUserDefaults. Since it is an array of strings, saving and retrieving it that way should work fine and would be easier than dealing with the iOS filesystem.
Edit:
If you really want to save it in the filesystem, look into the NSKeyedArchiver method + (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path and the NSKeyedUnarchiver method + (id)unarchiveObjectWithFile:(NSString *)path.
Edit 2:
As ondmike pointed out, you need to use %s rather than %# for your -stringWithFormat: method call to work properly. Relevant documentation is String Format Specifiers

Save NSMutableArray to load when reopenning iphone app

I have a NSMutableArray, each item in this array is different class. In each class has many field such as CPPlot, identifier,... (I am using CorePlot to develop a stock application). Now I would like to store this NSMutableArray to load when user reopen application, this will load all the chart they used before.
I try to figure out how to do that in Stackoverflow. And I found out there were 2 solutions:
NSUserDefaults
SQLite database
In NSUserDefaults, when I want to store NSMutableArray, I must implement with NSKeyedArchiver to archive and unarchive array object, also do NSCoding protocol for each item in array object. But I can not do this solution because in each item, it has some fields from CorePlot library, so that I can not use NSCoding to these fields.
SQLite database, I can not use this solution because each item in array object is different class.
I would like to ask if any other solution to solve this problem?
I hope my words are clear enough to understand.
Thanks
I would suggest you figure out what kind of data is at the root of your CorePlot objects. If it is integers, then simply store them in NSUserDefaults, and then simply rebuild your NSMutableArray on re-opening the app. Another option is to store your items in a separate plist file.
Use this method to save:
- (NSArray *)applicationDataFromFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirecotiresInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory
stringByAppendingPathComponent:fileName];
NSArray *myData = [NSArray arrayWithContentsOfFile:appFile];
return myData;
}
- (BOOL)saveToFileForStringArray:(NSMutableArray *)array
toFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if (!documentsDirectory) {
NSLog(#"Documents directory not found!");
return NO;
}
NSString *appFile = [documentsDirectory
stringByAppendingPathComponent:fileName];
return ([array writeToFile:appFile atomically:YES]);
}

Saving a single NSMutableDictionary in a plist

I have one dictionary I need to save into a plist. The paletteDictionary always returns nil:
- (void)saveUserPalette:(id) sender
{
[paletteDictionary setObject:matchedPaletteColor1Array forKey:#"1"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"UserPaletteData.plist"];
// write plist to disk
[paletteDictionary writeToFile:path atomically:YES];
}
I'm reading the data back in a different view like:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"UserPaletteData.plist"];
NSMutableDictionary *plistDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:path];
if(plistDictionary==nil ){
NSLog(#"failed to retrieve dictionary from disk");
}
Can you mention what object is "matchedPaletteColor1Array". I believe, its some custom class object. With my knowledge the writable objects must conform to NSCoding, which NSString,NSDate etc are already, So in given code, setting "matchedPaletteColor1Array" as some string will work.
You can look at following post to make your object NSCoding enabled. objects conforming to nscoding will not writetofile
Run your application in the simulator and browse to the following path:
~/Library/Application Support/iPhone Simulator/User/Applications/{A GUID}/Documents
Where A GUID will be a string like this: 06430A38-AFAC-4C68-8F39-DBD6C81A5AA6 (it's probably the Last Modified folder).
Verify that UserPaletteData.plist is present and load it up in Property List Editor.app to verify that it contains some data.
Also make sure that the you use only the following data types in your dictionary otherwise it will fail to write to a plist: (NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary).
To verify that the dictionary you are attempting to save to disk is valid for a plist, try the following:
for (id key in paletteDictionary)
{
NSLog(#"key: %#, value: %#, class: %#", key, [paletteDictionary objectForKey:key], NSStringFromClass([[paletteDictionary objectForKey:key] class]));
}
That should tell you if any of your objects are the wrong data type for a plist.
If that is still not helping, then you should make sure that paletteDictionary has been alloc/init'ed before saveUserPalette is called.
Check that you are allocating (alloc/init) paletteDictionary before you use it.

iPhone SDK: How do I properly save user-inputted information into a .plist or other file?

I've looked through the SDK documentation and through other questions that have been asked, and I am still a little confused on how exactly to do this. I had been previously been working with the following code, though it does not give the desired result of a .plist file. Besides mentioning the IBAction in the header files in this code in the .m file, is there anything else that needs to be added or anothe method I should be taking? Thanks!
My Code:
- (IBAction)fedDog {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"dogsFedDays.plist"];
NSMutableArray *dogsFedSave = [NSMutableArray arrayWithCapacity: 100];
for (int i = 0; i < 100; i++) {
NSDictionary *myDict = [[NSDictionary alloc] initWithObjectsAndKeys:
date[i], #"string",
fed[i], #"Yes",
nil];
[dogsFedSave addObject:myDict];
[myDict release];
}
if (![dogsFedSave writeToFile:path atomically:YES])
NSLog(#"not successful in completing this task");
}
I'm assuming that -writeToFile is returning NO so you're seeing your NSLog statement (correct me if I'm wrong). If that's the case, then the issue must be that some object in either your date array, or fed array is not any of the allowed object types for property lists which includes: NSString, NSData, NSArray, or NSDictionary. NSNulls are not allowed. From the docs for writeToFile:
This method recursively validates that
all the contained objects are property
list objects before writing out the
file, and returns NO if all the
objects are not property list objects,
since the resultant file would not be
a valid property list.

Plist not saving from dictionary (to Documents)

I've been trying to save a plist of a NSDictionary to my app's Documents folder. I haven't tried this on the device yet but I'd like it to work on the simulator for testing purposes. The [self createDictionaryFromChoreList] method just creates a NSDictionary from some data in another class of mine. I've pretty much copied/pasted this code from the web documents and when I go to see if the file was saved or not, I find that it isn't. Here is the method block.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistName = [[NSString alloc] initWithFormat:#"%#chores.plist", self.firstName];
NSString *path = [documentsDirectory stringByAppendingPathComponent:plistName];
NSDictionary *choresDictionary = [[NSDictionary alloc] initWithDictionary:[self createDictionaryFromChoreList]];
[choresDictionary writeToFile:path atomically:YES];
Any help is greatly appreciated. Thanks in advance.
-S
You should also capture the BOOL returned by writeToFile:atomically:. That will tell you if the write succeeded or not.
Also, are you sure you are looking in the right documents folder? If you have more than one app in the simulator its easy to open the wrong app's documents folder in the Finder. I did that once and it cost me a couple of hours of frustration.
Edit01:
writeToFile:atomically: returning false explains why no file exist. The simplest explanation is that something in the dictionary is not a property list object.
From the NSDictionary docs:
This method recursively validates that
all the contained objects are property
list objects (instances of NSData,
NSDate, NSNumber, NSString, NSArray,
or NSDictionary) before writing out
the file, and returns NO if all the
objects are not property list objects,
since the resultant file would not be
a valid property list.
It just takes one non-plist object buried deep in a dictionary to prevent it from being converted to a plist.
Don't forget serialize the plist data:
Here is a snippet of code that I use for writing information to a plist
NSString *errorString;
NSData *data = [NSPropertyListSerialization dataFromPropertyList:plistDict
format:NSPropertyListXMLFormat_v1_0
errorDescription:&errorString];
[plistDict release];
if (!data) {
NSLog(#"error converting data: %#", errorString);
return NO;
}
if ([data writeToFile:[XEraseAppDelegate loadSessionPlist] atomically: YES]) {
return YES;
} else {
NSLog(#"couldn't write to new plist");
return NO;
}
This is something I whipped up really quickly and it correctly writes a plist directory of name and company to the documents directory. I have a feeling your dictionary creation method might have an issue. Try this out for yourself, then add your code and make sure it works.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *plistDirectory = [paths objectAtIndex:0];
NSString *plistPath = [plistDirectory stringByAppendingPathComponent:#"userCompany.plist"];
NSArray *userObjects = [[NSArray alloc] initWithObjects:#"Joe", #"Smith", #"Smith Co", nil];
NSArray *userKeys = [[NSArray alloc] initWithObjects:#"First Name", #"Last Name", #"Company", nil];
NSDictionary *userSettings = [[NSDictionary alloc] initWithObjects:userObjects forKeys:userKeys];
[userSettings writeToFile:plistPath atomically:YES];
Is it correct, that the name of file your writing to is:
SOEMTHINGchores.plist?
Created via:
NSString *plistName = [[NSString alloc] initWithFormat:#"%#chores.plist", self.firstName];
Also, what is the output of:
[choresDictionary print];
Some additional info would help to debug this.
Where exactly are you looking for the file?
I have the exact same code and it works fine for me.
Just that I have to dig deep to get the file. Something like:
/Users/myUserName/Library/Application Support/iPhone Simulator/User/Applications/0E62A607-8EEB-4970-B198-81CE4BDDB7AA/Documents/data.plist
And the HEX number in the path changes with every run. So I print the file path with every run.
Insert a break point at
NSDictionary *choresDictionary = [[NSDictionary alloc] initWithDictionary:[self createDictionaryFromChoreList]];
now when you step out drag your mouse over choresDictionary and check in the tooltip that its size is not 0x0 or you can simply do an NSLog of the choresDictionary
like NSLog(#"%#",choresDictionary); I think your dictionary has 0 key key value pairs thats why you are getting null into your documents folder.
Thanks,
Madhup
I was running into this issue as well. In my case it turned out that I was using NSNumbers for keys - which is not valid.