Write Array to a file ArchiveRootObject - iphone

NSMutableArray *esami = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the
//documents directory:
NSString *fullFileName = [NSString stringWithFormat:#"%#/new", documentsDirectory];
esami = [NSKeyedUnarchiver unarchiveObjectWithFile:fullFileName];
Esame *add=[[Esame alloc]initWithNome:materia voto:voto crediti:crediti anno:anno];
[esami addObject:add];
[NSKeyedArchiver archiveRootObject:esami toFile:fullFileName];
I can't understad why this code doesn't work..
If I use a file already written in my root directory I can add the new element to my array and write it but if I use another file (new in this case) it doesn't work.

I don't know why but I resolved this issue with this code
NSMutableArray *esami = [NSKeyedUnarchiver unarchiveObjectWithFile:fullFileName];
if(esami.count==0){
NSMutableArray *esamiNew=[[NSMutableArray alloc] init];
[esamiNew addObject:[[Esame alloc]initWithNome:materia voto:voto crediti:crediti anno:anno]];
[NSKeyedArchiver archiveRootObject:esamiNew toFile:fullFileName];
}
else{
[esami addObject:[[Esame alloc]initWithNome:materia voto:voto crediti:crediti anno:anno]];
NSLog(#"num %d",esami.count);
[NSKeyedArchiver archiveRootObject:esami toFile:fullFileName];
}
Does is it a bug??

Related

Saving Array To File Objective C

I've been stuck on this for ever and I finally figured it out and now just out of the blue it stopped working again...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/scoreCards.dgs",documentsDirectory];
NSMutableArray *savedArrayOfScorecards = [[NSMutableArray alloc]init];
savedArrayOfScorecards = [NSMutableArray arrayWithContentsOfFile:filePath];
[savedArrayOfScorecards addObject:currentScoreCard];
[savedArrayOfScorecards writeToFile:filePath atomically:YES];
The file scoreCards.dgs is not even getting created...
What am I doing wrong?
There could be a couple things going wrong here.
1) The kind of data you're storing in the array might not be encodable or archive-able to a file. And the code snippet you included doesn't give a good hint as to what kind of data you're trying to save. If you have custom objects in your array (i.e. things that are not NSString, NSNumber, NSDate, etc.), then that's definitely the problem. There are plenty of questions here on StackOverflow that might help you solve this issue.
2) Your array's filepath could be bogus. For example, you're not checking to see if "documentsDirectory" is nil or valid or writeable.
3) Also possible, but not likely, "savedArrayOfScorecards" might be a nil array. You should do error checking to make sure "savedArrayOfScorecards" was instantiated and that there is more than one object in the array.
Your problem is, that although you create an array, before reading the file it is getting nil-ed on your call to:
savedArrayOfScorecards = [NSMutableArray arrayWithContentsOfFile:filePath];
So, because this savedArrayOfScorecards is now nil, your call to write it to a file is not doing anything.
You should load the array to another variable, and check it being nil, and create the new array only if the one read from the file is nil. Something like this:
NSMutableArray *savedArrayOfScorecards = [NSMutableArray arrayWithContentsOfFile:filePath];
if (!savedArrayOfScorecards) {
savedArrayOfScorecards = [[NSMutableArray alloc]init];
}
Are you sure the file exists when loading it?
savedArrayOfScorecards = [NSMutableArray arrayWithContentsOfFile:filePath];
This line creates a new NSMutableArray from the file. If the file does not exist, it returns nil. writeToFile is then sent to nil and nothing would happen.
Add a check to see if it's nil and create a new array if it is:
NSMutableArray *savedArrayOfScorecards = [NSMutableArray arrayWithContentsOfFile:filePath];
if(savedArrayOfScorecards == nil) savedArrayOfScorecards = [NSMutableArray array];
[savedArrayOfScorecards addObject:currentScoreCard];
[savedArrayOfScorecards writeToFile:filePath atomically:YES];
NSMutableArray is not a property-list-compliant format. You must use an NSArchiver to make it plist compliant.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/scoreCards.dgs",documentsDirectory];
NSMutableArray *savedArrayOfScorecards = [[NSMutableArray alloc]init];
savedArrayOfScorecards = [NSMutableArray arrayWithContentsOfFile:filePath];
[savedArrayOfScorecards addObject:#"ALLLAALLAAALLA"];
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archive = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
[archive encodeObject:savedArrayOfScorecards forKey:#"Scorecards"];
[archive finishEncoding];
BOOL result = [data writeToFile:filePath atomically:YES];
NSLog(result ? #"YES" : #"NO");
The correct answers are already here, just adding a better solution:
NSFileManager* fileManager = [NSFileManager defaultManager];
NSMutableArray* array;
if ([fileManager fileExistsAtPath:filePath]) {
array = [NSMutableArray arrayWithContentsOfFile:filePath];
NSAssert(array != nil, #"Invalid data in file.");
}
else {
array = [[NSMutableArray] alloc] init];
}
[array addObject:currentScoreCard];
[array writeToFile:filePath atomically:YES];

Displaying a score from highest to lowest

My score is displaying just not in the correct order. I've been trying to make a method that uses #selector(compare:) but have had no such luck.
Here's the code I'm working with and I'm wanting to display it from highest to lowest. I'm also wanting to have it so that if you load the app for the first time it creates an empty array so that if the user tries to look at the highscores it doesn't crash the app.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *scoresListPath = [documentsDirectory stringByAppendingPathComponent:#"scores.plist"];
scoresList = [[NSMutableArray arrayWithContentsOfFile:scoresListPath] retain];
if (scoresList == nil) {
scoresList = [[NSMutableArray array] retain];
}
and
- (void)addHighScore:(float)finalScore {
[scoresList addObject:[NSNumber numberWithFloat:finalScore]];
[scoresList sortUsingSelector:#selector(compare:)];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *scoresListPath = [documentsDirectory stringByAppendingPathComponent:#"scores.plist"];
[scoresList writeToFile:scoresListPath atomically:YES];
}
The reason your code is failing is because arrayWithContentsOfFile: returns an immutable array even though it is called on NSMutableArray. You should make a mutable copy of the array that you read of the file like this,
scoresList = [[NSArray arrayWithContentsOfFile:scoresListPath] mutableCopy];
This will give you an NSMutableArray object which can be added to.
Not sure about lowest but,you can use GKLeaderBoardViewController class for counting Highest Score.For more details I suggested you to read below link.Thanks
http://developer.apple.com/library/ios/#documentation/GameKit/Reference/GKLeaderboardViewController_Ref/Reference/Reference.html

Saving a NSMutableArray into a txt-file / Loading txt-file back into NSMutableArray

I had a look around, trying to find a straightforward method for first saving a MutableArray (which will contain different text arrays from UITextViews with returns etc.) into a txt-file and then loading the txt-file back into my MutableArray.
I didn't manage to come up with the reverse method (loading the text-file) and was wondering how I should go about this. I'm sure txt files and mutable arrays are not really compatible, especially if I want the MutableArray to hold various text strings from UITextViews.
Is there a way to mark the beginning of one section in a mutable array and the beginning of the next in a txt file? The aim would be to be able to edit the txt file both in the program and in a simple text editor without messing up the structure of the mutable array.
Can I use a certain special character (not \n obviously) in my text file so as to separate different objects?
Here is what I've come up with so far. Sorry, I'm a beginner and it's very basic. The first problem is that I get the error message 'NSMutableArray' may not respond to '-writeToFile:atomically:encoding:error:'. Next, I have no idea how to load the txt back into my Array. Finally, I'd like to come up with a way to separate the arrays in the txt so that it remains editable, but that would be the absolute icing. Perhaps a solution would be to save each Object in an Array in a separate txt file and then load each txt into the array?
// GENERATE ARRAY
NoteBook = [[NSMutableArray alloc] init];
for (int temp = 0; temp < 3; temp++) {
[NoteBook insertObject:#"Title\n\n Line1\nLine2..." atIndex:temp];
}
// SAVING MY MUTABLE ARRAY
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
NSError *error;
BOOL succeed = [NoteBook writeToFile:[documentsDirectory stringByAppendingPathComponent:#"myfile.txt"]
atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (!succeed){
// Handle error here
}
// LOADING TEXTFILE AND PUT IT INTO A MUTABLE ARRAY
// NO IDEA... how to do this
Convert your arrays into strings, and vice versa, using, e.g.,
NSString* arrayText = [NoteBook componentsJoinedByString: #"<your-favourite-separator-string>"];
the write to file using [arrayText writeToFile...]
After reading a string back from a file, use
Notebook = [arrayText componentsSeparatedByString: #"<your-favourite-separator-string>"];
Lastly, don't do this. Save your array directly to a property list (read up on those) or JSON or some other structured data format.
Why not just turn the mutable array into JSON and write that string to a file? The inverse is to read the string from file and turn back into an array using the JSON parser. json-framework is very easy to use.
A benefit would be that you could create or modify your array by editing text files as long as you write valid JSON.
make NSMutableArray to NSArray .because NSMutableArray does not have writeToFile .
retriev array from file
NSArray *theCatalogInfo=nil;
NSString *theCatalogFilePath = [NSString stringWithFormat:#"%#/Documents/",NSHomeDirectory()];
theCatalogFilePath = [theCatalogFilePath stringByAppendingString:kCatalogCachePath];
if(nil!=theCatalogFilePath)
{
theCatalogInfo=[[NSArray alloc]initWithContentsOfFile:theCatalogFilePath];
}
Save array To file
NSString *theCatalogFilePath = [NSString stringWithFormat:#"%#/Documents/",NSHomeDirectory()];
theCatalogFilePath = [theCatalogFilePath stringByAppendingString:kCatalogCachePath];
[**YourArray** writeToFile:theCatalogFilePath atomically:YES];
Have a look at following three methods to create a text file, write to it and read the data from it.
The key is to store the different objects separated by space. And you should get it very simple.
-(void)createFile
{
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Sample.txt"];
NSFileManager * file_manager = [NSFileManager defaultManager];
if(![file_manager fileExistsAtPath:filePath])
{
[file_manager createFileAtPath:filePath contents:nil attributes:nil];
NSString *content = #"NULL NULL NULL";
[content writeToFile:filePath
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
}
}
-(void)writeToFile
{
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Sample.txt"];
NSString *content = [NSString stringWithFormat:#"%# %# %#", obj1, obj2, obj3];
[content writeToFile:filePath
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
}
-(void)readFromFile
{
objects = [[NSArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Sample.txt"];
if (filePath) {
NSString *myText = [NSString stringWithContentsOfFile:filePath encoding:NSASCIIStringEncoding error:nil];
if (myText) {
objects = [myText componentsSeparatedByString:#" "];
}
}
}
if your nsarray contains nsdictionary, nsarray, nsstring, nsnumber, nsdata or nsdate objects (no custom objects, int's, etc) you can simply write the contents of your mutable array to a plist file.
this will maintain the data structure you have and you can simply read that data right into an array. How I do it in a couple of my data classes is
NSArray *tempArray = [NSArray arrayWithContentsOfFile:[Utils getFileLocation]];
if (tempArray == nil) {
yourArray = [[NSMutableArray alloc] init];
} else {
yourArray = [[NSArray deepMutableCopy:tempArray] retain];
}

Trouble decoding with NSKeyedUnarchiver

I am writing an app targeted at iOS 4.0 on XCode 3.2.3 where I store some data when the app closes using NSCoder protocol. Saving seems to work fine, the problem is retrieving the data from the saved files. My save method looks like this:
-(void)saveMusicalWorksToMemory{
// create the save paths
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *mwPath = [documentsDirectory stringByAppendingPathComponent:kMusicalWorksLocalFileSuffix];
NSString *fwPath = [documentsDirectory stringByAppendingPathComponent:kFeaturedWorksLocalFileSuffix];
NSMutableData *musicalWorksData;
NSMutableData *featuredWorksData;
NSKeyedArchiver *mwEncoder;
NSKeyedArchiver *fwEncoder;
musicalWorksData = [NSMutableData data];
featuredWorksData = [NSMutableData data];
mwEncoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:musicalWorksData];
fwEncoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:featuredWorksData];
// encode the objects
[mwEncoder encodeObject:musicalWorks forKey:kMusicalWorksArchiveKey];
[fwEncoder encodeObject:featuredWorks forKey:kFeaturedWorksArchiveKey];
[mwEncoder finishEncoding];
[fwEncoder finishEncoding];
// write to files
[musicalWorksData writeToFile:mwPath atomically:YES];
[featuredWorksData writeToFile:fwPath atomically:YES];
[mwEncoder release];
[fwEncoder release];
}
And here is the method where I read from the files:
-(void)loadMusicalWorksFromMemory{
// get the path to the locally saved data
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *mwPath = [documentsDirectory stringByAppendingPathComponent:kMusicalWorksLocalFileSuffix];
NSString *fwPath = [documentsDirectory stringByAppendingPathComponent:kFeaturedWorksLocalFileSuffix];
NSFileManager *fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:mwPath] && [fileManager fileExistsAtPath:fwPath]){
NSMutableData *mwData;
NSMutableData *fwData;
NSKeyedUnarchiver *mwDecoder;
NSKeyedUnarchiver *fwDecoder;
NSMutableArray *tempMusicalWorks;
NSMutableArray *tempFeaturedWorks;
// unarchive the file data
mwData = [NSData dataWithContentsOfFile:mwPath];
fwData = [NSData dataWithContentsOfFile:fwPath];
mwDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:mwData];
fwDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:fwData];
tempMusicalWorks = [mwDecoder decodeObjectForKey:kMusicalWorksArchiveKey];
tempFeaturedWorks = [fwDecoder decodeObjectForKey:kFeaturedWorksArchiveKey];
[mwDecoder finishDecoding];
[fwDecoder finishDecoding];
[mwDecoder release];
[fwDecoder release];
// restore the content
[self setMusicalWorks:tempMusicalWorks];
[self setFeaturedWorks:tempFeaturedWorks];
}else{
NSLog(#"MusicalWorkManager::loadMusicalWorksFromMemory - No file found at given path");
}
}
The weird thing is that when reading the data from memory and debugging, I see that mwData and fwData are in fact not nil, and have roughly the right size proportions to each other (about 2:1). The problem is though that the decoded arrays (tempMusicalWorks and tempFeaturedWorks) have zero entries (not nil though). This leads me to believe that the problem is actually in the decoding.
For the record, I have also checked that items are being saved in the saveMusicalWorksToMemory() method. The arrays I am passing in through this method are indeed populated with stuff. Also, I have checked that I am implementing the initWithCoder() and encodeWithCoder() methods properly for the objects being encoded and decoded.
Any hints? I'm really lost on this one.
Thanks!
-Matt

can't figure out why archiveRootObject is failing to write file

this seems to work fine in the simulator but on the device the files are not being written.
here's the code.
-(void)saveOld{
NSArray *saveState = [NSArray arrayWithObjects:headArray,dropQArray,[NSNumber numberWithInt:dropLimit],[NSNumber numberWithInt:dropCount],[NSNumber numberWithInt:score],[NSNumber numberWithInt:level],[NSNumber numberWithInt:maxChain],nil];
NSMutableString *path = [[NSHomeDirectory() mutableCopy]autorelease];
[path appendString:#"/saveState"];
BOOL saved = [NSKeyedArchiver archiveRootObject:saveState toFile:path];
NSLog(#"did save state %d",saved);
path = [[NSHomeDirectory() mutableCopy]autorelease];
[path appendString:#"/isSaveState"];
saved = [NSKeyedArchiver archiveRootObject:[NSNumber numberWithBool:1] toFile:path];
NSLog(#"did save state %d",saved);
}
There is no home directory on the iPhone :D
You should use this instead:
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
This will give you the basic documents directory, append strings to it then.