2

Im writing a text editor app and im trying to store a NSString as NSData in files in the documents folder, for example i want to be able to store a file "myText.java".

My code work on the Simulator. However, on the device a file seems to be created, but when I later try to load the data from the files i get nothing.

Do i have to set some project setting to enable the documents directory on device or is my code wrong?

Here is my store code:

-(void) saveFile:(NSString*)file{
    if (![file isEqual:@"Empty"]) {
        NSArray *paths = NSSearchPathForDirectoriesInDomains
        (NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *fullFilePath = [documentsDirectory stringByAppendingPathComponent:file];

        [[NSFileManager defaultManager] removeItemAtPath: fullFilePath error: nil];
        NSLog(@"File: %@", fullFilePath); 
        //Above LOGS: /var/mobile/Applications/2310F459-282C-4488-AE24-D5795168F85A/Documents/fg

        //save content to the documents directory
        NSLog(@"Saving: %@", codeView.text);
        // Logs the data i want to store
        [[codeView.text dataUsingEncoding:NSASCIIStringEncoding] writeToFile:fullFilePath atomically:YES];
    }
}

Here is my load file code:

-(void) loadFile:(NSString*)filename{
    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 *file = [documentsDirectory stringByAppendingPathComponent:filename];
    if ([[NSFileManager defaultManager] fileExistsAtPath:file]) {
        NSLog(@"File found");
        //Yes the file is found

        theDelegate.fileData = [NSData dataWithContentsOfFile:file];
        NSLog(@"Data:%@",[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:file] encoding:NSASCIIStringEncoding]);
        // On device and simulator data is found

        [theDelegate.codeView setText:[[NSString alloc] initWithData:theDelegate.fileData encoding:NSASCIIStringEncoding]];
        //codeView does not get updated with the data.
        //NSLog([[NSString alloc] initWithData:theDelegate.fileData encoding:NSASCIIStringEncoding]);
        [theDelegate setTitle:filename];
        [theDelegate setHasOpenFile:YES];
        [theDelegate.codeView setEditable:theDelegate.hasOpenFile];
        [theDelegate.codeView setNeedsDisplay];
        [self setLanguage:filename];
    }else{

        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"File error!" message:@"An error occured when trying to load the selected file." delegate:self cancelButtonTitle:@"OK!" otherButtonTitles:nil, nil];
       [alert show];
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
David Karlsson
  • 9,396
  • 9
  • 58
  • 103
  • Check the return value of `writeToFile:atomically:`. Also, you say you want the file saved as `myText.java` but the log shows that `file` is just `fg`. – rmaddy May 22 '13 at 19:29
  • I'm trying to find where you go wrong, but just as an aside, this code is somewhat horrible. `saveFile` uses `file` for the filename, `loadFile` uses `filename` for the name, and `file` for the whole path. This is asking for errors. – uvesten May 22 '13 at 19:33
  • thanks for your remarks, I will take care of it – David Karlsson May 23 '13 at 11:10

2 Answers2

2

No, you don't have to enable a setting to use the documents directory. There might or might not be an error with your code, in any case it's hard to read and not very clean (apologies for saying this.)

Try to do everything just once. I took the liberty of rewriting your code a bit, to clean it up. I then tested it with a sample app on my phone, and it works perfectly.

Code rewrite:

-(void) saveFile:(NSString*)filename{
    if (![filename isEqual:@"Empty"]) {

        NSString *fullFilePath = [self getFullFilePath:filename];

        [[NSFileManager defaultManager] removeItemAtPath: fullFilePath error: nil];
        NSLog(@"File: %@", fullFilePath);

        //save content to the documents directory
        NSLog(@"Saving: %@", self.codeView.text);
        // Logs the data i want to store
        [[self.codeView.text dataUsingEncoding:NSASCIIStringEncoding] writeToFile:fullFilePath atomically:YES];
    }
}

The above code is fine, after adding the helper function.

-(void) loadFile:(NSString*)filename{

    NSString *fullFilePath = [self getFullFilePath:filename];

    if ([[NSFileManager defaultManager] fileExistsAtPath:fullFilePath]) {
        NSLog(@"File found");
        //Yes the file is found

        NSLog(@"Data:%@",[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fullFilePath] encoding:NSASCIIStringEncoding]);
        // On device and simulator data is found

        [theDelegate.codeView setText:[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fullFilePath] encoding:NSASCIIStringEncoding]];

        [theDelegate setTitle:filename];
        [theDelegate setHasOpenFile:YES];
        [theDelegate.codeView setEditable:theDelegate.hasOpenFile];
        [theDelegate.codeView setNeedsDisplay];
        //[self setLanguage:filename];
    }else{

        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"File error!" message:@"An error occured when trying to load the selected file." delegate:self cancelButtonTitle:@"OK!" otherButtonTitles:nil, nil];
        [alert show];
    }
}

In your old code, there might have been a problem with theDelegate.fileData = [NSData dataWithContentsOfFile:file];, if the reference is weak. Since I presume you'll always have the code in codeView, it seems unnecessary to first store it in a member variable. Also, this might lead to more bugs.

The following is a helper function, so that you don't do the exact same thing in both functions, as it might lead to bugs.

-(NSString*) getFullFilePath:(NSString*)filename {
    NSArray *paths = NSSearchPathForDirectoriesInDomains
    (NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *fullFilePath = [documentsDirectory stringByAppendingPathComponent:filename];

    return fullFilePath;

}
uvesten
  • 3,365
  • 2
  • 27
  • 40
1

Are you taking care that the filenames passed to loadFile: and saveFile: are exactly the same, including capitalization? Mac OS X (and by extension, the iOS simulator) uses case-insensitive filenames, while iOS is case sensitive and treats SomeFile.txt and somefile.txt as two different things.

bdesham
  • 15,430
  • 13
  • 79
  • 123