objective-c simple nsarray writeToFile issue - objective-c

[wordlist writeToFile:[[NSBundle mainBundle]
pathForResource:#"wordlist" ofType:#"txt"] atomically: YES];
wordlist is a NSMutableArray, and the rest you know what.
The problem is that nothing is saved in wordlist.txt when I run the codes in Xcode. In front of this code nslog shows that there are 4 objects in wordlist. How come?
Edit:
Right!
These codes work!:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *yourArrayFileName = [documentsDirectory stringByAppendingPathComponent:#"wordlist.txt"];
[wordlist writeToFile:yourArrayFileName atomically:YES];
NSLog (#"%#", yourArrayFileName);
Edit 29 august 2011.
NSString *documentsDirectory = #"/Users/YOURNAME/Desktop/";
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"norsk.txt"];
NSString *content = #"æ ø å";
BOOL ok = [content writeToFile:appFile atomically:YES encoding:NSUnicodeStringEncoding error:nil];
if (!ok) {
NSLog(#"Error writing file !");
}
also works!

You can't write in you app's bundle.
You need to write in the user's directory. You can know more about it in this question.
There's three directory you can write in
NSDocumentDirectory : the document directory. The user will be able to see these file. This should be for user files only. Backed up by iTunes.
NSCachesDirectory : the cache directory is where you place things you app may need in the future, but that you can reconstruct. Not backed up by iTunes.
NSApplicationSupportDirectory : the application support is where you place your essential files for your application. Backed up by iTunes.

Related

Objective-c load and write plist - error

Hi I'm practicing with plists and I learned that there are 2 different ways to load them
FIRST METHOD:
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documents = [path lastObject];
NSString *filePath = [documents stringByAppendingPathComponent:#"test.plist"];
self.array = [NSArray arrayWithContentsOfFile:filePath];
SECOND METHOD:
NSString *filePath = [[NSBundle mainBundle]pathForResource:#"Ingredients" ofType:#"plist"];
self.array = [NSArray arrayWithContentsOfFile:filePath];
I don't understand clearly which way it's best... but I noticed that if I use the second one, I can't write in the plist. can anyone tell me more about it? which is the best and correct way? What's the difference?
i'm doing some tests and i have some code working only with one method...
//using this code the nslog will print null
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"Ingredients.plist"];
ingredients = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"ingredients:%#", self.ingredients);
//using this code the nslog will print the content of the array
NSString *filePath = [[NSBundle mainBundle]pathForResource:#"Ingredients" ofType:#"plist"];
ingredients = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"Authors:%#", self.ingredients);
First Method
Your app only (on a non-jailbroken device) runs in a "sandboxed" environment. This means that it can only access files and directories within its own contents. For example Documents and Library.
Reference iOS Application Programming Guide.
To access the Documents directory of your applications sandbox, you can use the following:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
This Documents directory allows you to store files and subdirectories your app creates or may need.
To access files in the Library directory of your apps sandbox use (in place of pathsabove):
[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]
Second Method
The Second Method is used to write the file in the Apps main bundle.
The main bundle is the bundle that contains the code and resources for the running application. If you are an application developer, this is the most commonly used bundle. The main bundle is also the easiest to retrieve because it does not require you to provide any information.
It is better to copy the file from App Main Bundle to App Document Directory and then use the document directories path to read/write file.
If you are using the first method you need to copy the file from your main resources to the Documents Directory.
Code to Copy file from app bundle to App's Document Directory
#define FILE_NAME #"sample.plist"
// Function to create a writable copy of the bundled file in the application Documents directory.
- (void)createCopyOfFileIfNeeded {
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:FILE_NAME];
success = [fileManager fileExistsAtPath:filePath];
if (success){
return;
}
// The writable file does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:FILE_NAME];
success = [fileManager copyItemAtPath:defaultDBPath toPath:filePath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable file with message '%#'.", [error localizedDescription]);
}
}
Sample Code Dropbox Link

How to save text/data in cocoa/xcode to a file?

i'm sorry for the obvious question, but is there something i should be careful about when writing data to a file, because my program can read the data it just wrote, while the program is running, but the moment i stop it, the files become empty
tried using NSFileHandle, in order to write data with it, and close the file later, didn't help... currently, i'm using:
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:newArray];
[encodedObject writeToFile:string atomically:YES];
and no matter what i do, i can't get the simplest NSString to stay in the file permanently
what do i do?
Thanks #LetzFlow, but it didn't solve it just yet.
Now, i'm using:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
string = [NSString stringWithFormat:#"%d.rtf",fileName];
NSString *file = [documentsDirectory stringByAppendingPathComponent:string];
//NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:file];
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:newArray];
[encodedObject writeToFile:file atomically:YES];
//[fileHandle writeData:encodedObject];
//[fileHandle closeFile];
NSLog(#"%#",[NSString stringWithContentsOfFile:file encoding:NSStringEncodingConversionAllowLossy error:nil]);
to serialize an array of objects, and it the NSLog shows a valid array. Yet, when I look at the file later, or try to unserialize the array (like this):
NSString *stringX = [NSString stringWithFormat:#"%d.rtf",fileName];
NSData *encodedObjectX = [NSData dataWithContentsOfFile:stringX];
NSArray *newArrayX = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObjectX];
TurnigButton *button = [[newArrayX objectAtIndex:1] objectAtIndex:5];
NSLog(#"%d", button.idNum);
it just prints (null). (when they execute one after the other in a single run, it unserializes just fine)
I appreciate the help.
The question is WHERE do you write your file? Because you are not allowed to write files all over the system in iOS.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
The documents directory is usually a place were you can write files, so you might want to give that a try.

ObjC download file and save it to directory

Id like to "update" a local file from a server (save it to a directory).
I tried EVERYTHING! NOTHING WORKS! That's my last attempt:
NSURL *url = [NSURL URLWithString:#"http://www.doothie.com/QAFrameworks/QAUpdater.php"];
NSData *urlData = [NSData dataWithContentsOfURL:url];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"general.qa"];
NSString *str = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
[str writeToFile:filePath atomically:TRUE encoding:NSUTF8StringEncoding error:NULL];
Not sure if that's what you're trying to do, but you shouldn't try to download and replace a file that's in your Application bundle. Instead, download the file into the user's ~/Library/Application Support/<yourApplicationName>/<yourFiles>. Before using the file within your application bundle, check to see if the one with more current data is in the Application Support. If you application is installed for all users (within /Applications/), non-admin users wouldn't have the authority to change files within the app bundle. (And one should never assume every user runs with admin rights.)
Perhaps that's what's happening.
Additionally, you're loading everything into NSString. Does the file actually contain text?! If not, you might want to use NSData instead :
[[NSData dataWithContentsOfURL:url] writeToFile:filePath atomically:TRUE];

writeToFile:atomically only works first time

When my app starts, looks if a plist exists, if it doesn't it creates it.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"history.plist"];
success = [fileManager fileExistsAtPath:filePath];
if (success) {
NSArray *arr = [[NSArray alloc] initWithContentsOfFile:[documentsDirectory stringByAppendingPathComponent:#"history.plist"]];
for (NSDictionary *par in arr) {
[self.history addObject:[[Paradero alloc] initWithDictionary:par]];
}
} else {
[fileManager createFileAtPath:filePath contents:nil attributes:nil];
}
Now, when the user closes the app, to provide persistance I save the data to that file
- (void)applicationDidEnterBackground:(UIApplication *)application {
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"history.plist"];
NSLog(#"%#", filePath);
NSMutableArray *temparray = [[NSMutableArray alloc] initWithCapacity:5];
for (Paradero *parada in self.history) {
[temparray addObject:[parada asDictionary]];
}
NSLog(#"%#", temparray);
NSLog(#"%c",[temparray writeToFile:filePath atomically:NO]);
NSLog(#"yei");
}
The object is converted to a Dictionary with NSString, NSArrays so it can be saved to the file. The first time this ever happens, that means, the file was created, nothing on it, it works just fine, but when is time to save new data, it fails, no reason given.
Solved.
For the record:
The first issue was that i was testing on iOS5 Simulator, well, i don't know how to fix it there yet.
The real issue was because there was some NSNull around, so, I just needed to turn them into empty strings.
Remember to check for NSNulls, they are really a pain if they turn out from a web service.

Accessing NSDocumentDirectory on iPad Simulator

I've added a very simple .csv file to my app's NSDocumentDirectory using:
-(IBAction)exportModule:(id)sender{
NSString *fileName = #"exportedfile.csv";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *exportString = #"I've,been,exported";
NSData *testData=[exportString dataUsingEncoding:NSUTF8StringEncoding];
NSString *docDir = documentsDirectory;
NSString *completePath = [docDir stringByAppendingPathComponent:fileName];
[testData writeToFile:completePath atomically:YES];
if ([[NSFileManager defaultManager] fileExistsAtPath:completePath]) {
NSLog(#"Theres a file here!");
}
}
The app gets into the if statement printing "Theres a file here!", however I would like open the file and see if there were any problems in formatting the .csv.
If I were running on a physical device, I'd be able to open it up in iTunes and take a look there, but is there a way to examine the .csv while only using the simulator?
I have this at the beginning of all of my programs for using the simulator
NSLog(#"Documents: %#", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]);