Storing NSArray/NSMuatbleArray in File - iphone

I'm beginning to store an NSArray in file, but I keep getting nil as a response...
The Apple docs say that nil means your file doesn't exist, but I'm pretty sure mine does (I'm probably not building my path correctly)...
Here is the code that I use to store my NSArray in a file...
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"scorecards" ofType:#"dgs"];
NSArray *myArray = [[NSArray alloc] initWithObjects:#"J", #"ANA", #"MY", #"GDON", nil];
[myArray writeToFile:filePath atomically:YES];
NSArray *mynewArray = [NSArray arrayWithContentsOfFile:filePath];
NSLog(#"%#", [mynewArray objectAtIndex:2]);
I also took a screenshot of Xcode to show you guys that my file does exist...
The file is clearly saved in the group ScorecardsSaved and the file is called scorecards with the extension dgs (something I made up for my specific application - Dot Golf Scorecard - dgs)

Indeed, your file path uses the pathForResource method, thus it will point to a location in your application bundle, which is not writable.
Instead, you have to write to the application document directory on the device / simulator.
NSURL *documentsDirectory =
[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSURL *fileURL = [documentsDirectory
URLByAppendingPathComponent:#"storecards.dgs"];
So if your bundle version of the document contains some seed data, copy it to the app documents directory first.

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:FILE_NAME];
[myArray writeToFile:filePath atomically:YES];

Related

Settings.plist iOS

I have a Settings.plist file in my iOS application. I access it using this code below:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Settings.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error];
}
NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
But, say I make some changes to the Settings.plist file in my application, like add another row. Then if I publish it, users that already have my app will have an out dated Settings.plist file. Any ideas on a workaround or anything? I have tried accessing the Settings.plist file straight from the NSString *bundle, but then the values don't "save".
You need to do a file modification date check, see my answer here. Then if the modification date is later than the last checked date, download the Settings.plist file and replace it in the users app.

storing pdf on local doesnt work in iphone

I'm new with iPhone development. I want to download a pdf using url and want to store it in a local folder.
Here is my code:
NSData *d = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://demo.com/ebookapplication/book_pdf/20111108094614hii.pdf"]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"myfile.pdf"];
[d writeToFile:path atomically:YES];
if (![[NSFileManager defaultManager] fileExistsAtPath:path])
{
NSString *myPathInfo = [[NSBundle mainBundle] pathForResource:#"myfile" ofType:#"pdf"];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager copyItemAtPath:myPathInfo toPath:path error:NULL];
}
NSURL *pdfurl = [NSURL fileURLWithPath:path];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:pdfurl];
[detail.bookweb loadRequest:requestObj];//to display data in web view
This code is working for display pdf in web view using url, but it doesn't work for storing pdf in our local system. Actually I want to store these downloaded pdf in one folder and and display it in library format. Please help.
-writeToFile:Atomically has already placed your file in the folder you've specified in the -copyItemAtPath:toPath: method, and is thus redundant. The document was already in the documents directory folder, you then copied it over to the same directory! I think that's your problem.
EDIT:
This Line HERE:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"myfile.pdf"];
specifies your path.
You can NSLog it with this line: NSLog(#"Document Path = %#", path);
As for your library comment, it shouldn't be that hard. My app, which basically does this already, wires
AQGridView: https://github.com/AlanQuatermain/AQGridView
And Apple's Docwatcher class from DITableView: http://developer.apple.com/library/ios/samplecode/DocInteraction/Listings/Classes_DITableViewController_h.html
Together to create an app that trolls the documents directory and adds files to an NSArray which are then displayed by the grid. A simpler approach would just be to use the DITableViewController though, considering it solves your problems, it's just the grid was for a little more pizzaz.

What am I doing wrong? NSFileManager woes

I'm currently building quite a large iPhone application. Bigger than I expected anyway. But that is beside the point, the overall idea of the application is to grab JSON from a web service, sort it all into custom NSObject's that are linked together and then present.
This goes all well and good. But, because I want the user to be able to see this information on the device without an internet connection, I need to save the information that I am presenting into the Documents folder that each Application has.
I basically implemented the NSCoding protocol into all the custom NSObject's that would need it in order to save it into a subdirectory of the Documents directory.
This is all achieved through this function here.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"Data"];
NSString *dataFileString = [dataPath stringByAppendingPathComponent:#"Company.archive"];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataFileString]) //Does directory already exist?
{
MACompany *company = [MACompany sharedMACompany];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"Data"];
NSError *error;
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) //Does directory already exist?
{
if (![[NSFileManager defaultManager] createDirectoryAtPath:dataPath
withIntermediateDirectories:NO
attributes:nil
error:&error])
{
NSLog(#"Create directory error: %#", error);
}
}
NSString *dataFileString = [dataPath stringByAppendingPathComponent:#"Company.archive"];
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:company forKey:#"MACompany"];
[archiver finishEncoding];
[[NSFileManager defaultManager] createFileAtPath:dataFileString
contents:data
attributes:nil];
[archiver release];
[data release];
} else {
NSLog(#"File already exists, no need to recreate, not yet anyway");
}
}
I do the following request when the user first loads the application (application didFinishLaunchingWithOptions:) and when the user opens the application after being in the background (applicationWillEnterForeground:).
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"Data"];
NSString *dataFileString = [dataPath stringByAppendingPathComponent:#"Company.archive"];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataFileString]) //Does directory already exist?
{
NSLog(#"Create a new Company Request");
MAWebRequests *companyReq = [[MAWebRequests alloc] init];
[companyReq getCompanyDetails];
[companyReq release];
} else {
NSLog(#"Saved Company Needs to be Decoded applicationWillEnterForeground");
MACompany *company = [MACompany sharedMACompany];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"Data"];
NSString *dataFileString = [dataPath stringByAppendingPathComponent:#"Company.archive"];
NSData *data = [[NSData alloc] initWithContentsOfFile:dataFileString];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
[data release];
company = [unarchiver decodeObjectForKey:#"MACompany"];
[unarchiver finishDecoding];
[unarchiver release];
}
Now this works all well and good and I can pull from this file also. But, I can only grab the data stored in this file when I have Xcode's debugger attached to the application. As soon as is stopped, the data is corrupted and doesn't include the original data.
The data is still stored there, I can see the created file, but the actual data itself that is stored within the file is wrong...
Should I not be using the above logic to save the data to the file and then pull recreate the shared object?
Has anyone else tried to do such a thing and had success?
Is there any reason as to why I'm running into this weird issue?
Has anyone else had this issue?
Any help would be greatly appreciated, have been trying all sorts of different methods to get it to work and nothing has been able to get there. All I need to be able to do is be able to store the data there permanently until I need to update it...
I have resolved this issue by saving the MACompany object well before applicationDidEnterBackground:
Major thanks to #OleBegemann for his aid in finding where the issue nested.

write a dictionary to plist on iphone

I want to add a new dictionary to the existing plist file, how can I do that, I can read from the file, but with the same approach, writing doesn't work. My plist structure looks like this:
Root Array
|__item0 Dictionary
|__item1 Dictionary
|__item2 Dictionary
The code of writing to the file looks like this:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSString *plistPath = [documentDirectory stringByAppendingPathComponent:#"list.plist"];
if (![fileManager fileExistsAtPath:plistPath]) {
plistPath = [[NSBundle mainBundle] pathForResource:#"list" ofType:#"plist"];
}
NSMutableArray *dataRoot = [NSMutableArray arrayWithContentsOfFile:plistPath];
NSMutableDictionary *item = [[NSMutableDictionary alloc] init];
[item setObject:#"value1" forKey:#"1"];
[item setObject:#"value2" forKey:#"2"];
[item setObject:#"value3" forKey:#"3"];
[dataRoot addObject:item];
[dataRoot writeToFile:plistPath atomically:YES];
[item release];
Can anyone help me with this, thanks!
I have updated my code, but it still doesn't work...And the problem is list.plist file doesn't get copied to ~/Documents directory.
You are trying to write the main bundle which is no-no on iOS. Please read the A Few Important Application Directories.
But your coding boils down to the following:
Check if plist is not in Application_Home/Documents/
Copied original plist from main bundle is the answer to step 1 is false.
Open the plist in the Documents directory
Update NSMutableArray
Write to file the plist
I think code is not wrong.
Have you check plistPath, dataRoot, and item?
They have correct value?
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"list.plist"];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
bingoArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
}
[bingoArray writeToFile:filePath atomically:YES];
You can only save primitive types by default.
try out this link.
http://deadpanic.com/howtosave
He explains how to save any object to disk by using NSCoding protocol.
If you are working only with primitives then I apologize for wasting your time. But this is the path I took to write my custom stuff to disk. And I thought it was just an array issue.
Edit:
I just noticed... It looks like you are trying to write to an array in the Main Bundle. These files are read only.
You need to save a copy of the file in the Documents directory.
try this out to find the documents directory
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// Change your plistPath to be this
plistPath = [documentsDirectory stringByAppendingPathComponent:#"list.plist"];
[dataRoot writeToFile:plistPath atomically:YES];
put your plist in this folder and you can write to it.

What's the proper way to read/write to a plist?

In my app I store some user data in two .plist files which already contain some data, but the user can change it.
NSString *Path = [[NSBundle mainBundle] bundlePath];
NSString *DataPath = [Path stringByAppendingPathComponent:#"Settings.plist"];
NSMutableDictionary *tempDict = [[NSMutableDictionary alloc] initWithContentsOfFile:DataPath];
It works on the Simulator, but not on the device.
Can you help me, please?
Thank you!
You can't write to the bundle on the device, so you need to get the path to your Documents or Library directory.
- (NSString*)applicationDocumentsDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [paths lastObject];
}