report

How-To Read and Write to Files with iOS SDK (Objective-C)

Writing to files and reading from files is a time proven technique for data persistence and for data manipulation. IOS 5 provides APIs for reading and writing to files, it is a fundamental functionality of any computerized system. It is also a great way to persist data from one scene to another.

How the file system works


First I think it is important to give a little information on how the file system works on IOS devices. Instead of being able to access the file system directly as you would normally do, each app lives in its own sandbox. It is in this sandbox were you create, write to, read from and delete files.

IOS 5 Apps live in their own sandbox as do their files.
IOS 5 Apps live in their own sandbox as do their files.

Create the FileOps class


To write to files and, if necessary, create the directory and the file, you will need to create a new Objective-C class, FileOps. At least in regards to this tutorial. How you go implementing your code and logic is your business. Start by creating a new group in your project or create a new project if you haven’t one. It doesn’t matter what type of app you create, however I prefer using the Single-View Application template so not to get bogged down with extra resources. For the sake of this tutorial, I am naming the group Files.

Open the header file and create the following pointer variables. Also create the corresponding properties and methods and synthesize the properties in the implementation file.


//
// FileOps.h
// FileOperation
//
// Created by Kevin Languedoc on 11/28/11.
// Copyright (c) 2011 kCodebook. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface FileOps : NSObject{
NSFileManager *fileMgr;
NSString *homeDir;
NSString *filename;
NSString *filepath;
}

@property(nonatomic,retain) NSFileManager *fileMgr;
@property(nonatomic,retain) NSString *homeDir;
@property(nonatomic,retain) NSString *filename;
@property(nonatomic,retain) NSString *filepath;

-(NSString *) GetDocumentDirectory;
-(void)WriteToStringFile:(NSMutableString *)textToWrite;
-(NSString *) readFromFile;
-(NSString *) setFilename;
@end

The rest of the work on the FileOps class will be done in the FileOps implementation file.

Creating (Get) the Documents directory

To begin open the FileOps.m (implementation) file, we will need to know where the Documents folder is located and if need be, create it. This is where we will be storing our file and its contents. To get the Documents directory create the GetDocumentDirectory method that was declared in the header file.

-(NSString *)GetDocumentDirectory{
fileMgr = [NSFileManager defaultManager];
homeDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];

return homeDir;
}
...

First we set the fileMgr object to the defaultManager in the NSFileManager. Next we set the value for homeDir, which will the “Documents” sub directory, appended to the App directory that we will get by using the NSHomeDirectory() method.

Creating and Writing to files


Writing to files is easy with the NSFileManager. All we need to know is the name of the file to use and the path. The path we have already through the GetDocumentDirectory() method. To get the filename, I created a method, setFilename, that returns the filename as a NSString. Note I could have also used an accessor property.

-(void)WriteToStringFile:(NSMutableString *)textToWrite{
filepath = [[NSString alloc] init];
NSError *err;

filepath = [self.GetDocumentDirectory stringByAppendingPathComponent:self.setFilename];

BOOL ok = [textToWrite writeToFile:filepath atomically:YES encoding:NSUnicodeStringEncoding error:&err];

if (!ok) {
NSLog(@"Error writing file at %@\n%@",
filepath, [err localizedFailureReason]);
}

}
….
I start by initializing the filepath string and declare an error variable. Next I set the filepath using the self.GetDocumentDirectory() method with stringByAppendingPathComponent, followed by the name of the file to use: self.setFilename. The next line of code attempts to create the file, if it doesn’t exist and write the contents of the textToWrite parameter in the WriteToStringFile class method. When you set Atomically:YES, means that you write to a temp file before writing to the real file. This helps prevent file corruption.

Reading from Files


Reading from files is pretty much the same as writing. I reset the filepath in case a different path was used for a different operation. After creating an error variable and a variable, title, for the UIAlertView, I set the value of the filepath to the path of the Document directory, to which I append the filename. The return value is the contents of the file encoded as a string (NSUnicodeStringEncoding).
-(NSString *) readFromFile
{
filepath = [[NSString alloc] init];
NSError *error;
NSString *title;
filepath = [self.GetDocumentDirectory stringByAppendingPathComponent:self.setFilename];
NSString *txtInFile = [[NSString alloc] initWithContentsOfFile:filepath encoding:NSUnicodeStringEncoding error:&error];

if(!txtInFile)
{
UIAlertView *tellErr = [[UIAlertView alloc] initWithTitle:title message:@"Unable to get text from file." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[tellErr show];
}
return txtInFile;
}
...

The final bit is to setup the View Controller to get input from the user and save it to the file and to also read contents from the file to display on screen.

Display Contents in ViewController


Open the storyboard and add two labels, a textfield and two buttons. Lay them out like in following screenshot (Figure 2). Next Open the View Controller header file, add an IBOutlet connection for the output label: displayTxtFromFile; add another IBOutlet connection for the TextField: writeSomethingField. For the IBActions, add one for the Save button: saveTextToFile
and one for the Read button: getFromFile. Finally add a Delegate for the TextField by Ctrl+left mouse button from the TextField to the kcb View Controller object in the Storyboard (Figure 2).

Figure 2: Storyboard layout and connection in View Controller header file.
Figure 2: Storyboard layout and connection in View Controller header file.

Next in the implementation file, synthesize the two IBOutlets:


@synthesize displayTxtFromFile;
@synthesize writeSomethingField;


And implement the following IBAction methods:

- (IBAction)saveTextToFile:(id)sender {

FileOps *files = [[FileOps alloc] init];

[files WriteToStringFile:[self.writeSomethingField.text mutableCopy]];


}

In the saveTextToFile method, I create a FileOps object, *files and call the saveTextToFile method passing the value of the FieldText and converting it to a mutable string with mutableCopy.

-(BOOL) textFieldShouldReturn:(UITextField *) aTxtFld{
if(aTxtFld==self.writeSomethingField)
{
[aTxtFld resignFirstResponder];
}

return YES;
}

The above method is not associated with the file operations, but it is included to make the keyboard disappear when the user clicks on the Return button.

- (IBAction)getFromFile:(id)sender {
FileOps *readFile = [[FileOps alloc] init];
self.displayTxtFromFile.text = [readFile readFromFile];
}

The getFromFile IBAction method retrieves the text that was written to the text file. For the sake of simplicity I created a second FileOps object and I call the readFromFile to retrieve the text and add to the displayTxtFromFile label.

As the saying goes “That is all folks”!

App Output

Figure 3: App Output
Figure 3: App Output

FileOps.h

//
//  FileOps.h
//  FileOperation
//
//  Created by Kevin Languedoc on 11/28/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface FileOps : NSObject{
    NSFileManager *fileMgr;
    NSString *homeDir;
    NSString *filename;
    NSString *filepath;
    
   

}


@property(nonatomic,retain) NSFileManager *fileMgr;
@property(nonatomic,retain) NSString *homeDir;
@property(nonatomic,retain) NSString *filename;
@property(nonatomic,retain) NSString *filepath;

-(NSString *) GetDocumentDirectory;
-(void)WriteToStringFile:(NSMutableString *)textToWrite;
-(NSString *) readFromFile;
-(NSString *) setFilename;




@end

FileOps.m

//
//  FileOps.m
//  FileOperation
//
//  Created by Kevin Languedoc on 11/28/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//

#import "FileOps.h"

@implementation FileOps
@synthesize fileMgr;
@synthesize homeDir;
@synthesize filename;
@synthesize filepath;


-(NSString *) setFilename{
    filename = @"mytextfile.txt";
    
    return filename;
}

/*
 Get a handle on the directory where to write and read our files. If
 it doesn't exist, it will be created.
 */

-(NSString *)GetDocumentDirectory{
    fileMgr = [NSFileManager defaultManager];
    homeDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
    
    return homeDir;
}


/*Create a new file*/
-(void)WriteToStringFile:(NSMutableString *)textToWrite{
    filepath = [[NSString alloc] init];
    NSError *err;
    
    filepath = [self.GetDocumentDirectory stringByAppendingPathComponent:self.setFilename];
  
    BOOL ok = [textToWrite writeToFile:filepath atomically:YES encoding:NSUnicodeStringEncoding error:&err];
        
    if (!ok) {
        NSLog(@"Error writing file at %@\n%@",
              filepath, [err localizedFailureReason]);
            }
   
    }
/*
 Read the contents from file
 */
-(NSString *) readFromFile
{
    filepath = [[NSString alloc] init];
    NSError *error;
    NSString *title;
    filepath = [self.GetDocumentDirectory stringByAppendingPathComponent:self.setFilename];
    NSString *txtInFile = [[NSString alloc] initWithContentsOfFile:filepath encoding:NSUnicodeStringEncoding error:&error];
    
    if(!txtInFile)
    {
        UIAlertView *tellErr = [[UIAlertView alloc] initWithTitle:title message:@"Unable to get text from file." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [tellErr show];
    }
    return txtInFile;
}

@end

kcbViewController.h

//
//  kcbViewController.h
//  FileOperation
//
//  Created by Kevin Languedoc on 11/28/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface kcbViewController : UIViewController  <UITextFieldDelegate>{
    
}
@property (weak, nonatomic) IBOutlet UITextField *writeSomethingField;
- (IBAction)saveTextToFile:(id)sender;
@property (weak, nonatomic) IBOutlet UILabel *displayTxtFromFile;
- (IBAction)getFromFile:(id)sender;

@end

kcbViewController.m

//
//  kcbViewController.m
//  FileOperation
//
//  Created by Kevin Languedoc on 11/28/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//

#import "kcbViewController.h"
#import "FileOps.h"

@implementation kcbViewController
@synthesize displayTxtFromFile;
@synthesize writeSomethingField;

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    
    
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
}

- (void)viewDidUnload
{
    [self setWriteSomethingField:nil];
    [self setDisplayTxtFromFile:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
	[super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
	[super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

- (IBAction)saveTextToFile:(id)sender {
    
    FileOps *files = [[FileOps alloc] init];
  
    [files WriteToStringFile:[self.writeSomethingField.text mutableCopy]];
  
    
}
-(BOOL) textFieldShouldReturn:(UITextField *) aTxtFld{
    if(aTxtFld==self.writeSomethingField)
    {
        [aTxtFld resignFirstResponder];
    }
    
    return YES;
}
- (IBAction)getFromFile:(id)sender {
    FileOps *readFile = [[FileOps alloc] init];
    self.displayTxtFromFile.text = [readFile readFromFile];
}
@end

In Summary


There are several ways to write, save and read data using files, this article only focuses on one of them. Also depending on the type of file you are working with, there several different sub directories to save files and data to. I hope this tutorial has been useful.

More by this Author


Comments 21 comments

peterTheNewb 4 years ago

I have been reading and you-tubing quite a bit lately trying to get a handle on iOS dev and the clarity and simplicity (not to be confused with simplistic, which 99% of folks do) of you article puts it in the 'of high quality' class. Thanks! I hope I find more of your writings in future.


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Wow thanks Peter. I really appreciate your endorsement. I try to write tutorials that, as a programmer , I would find useful and hope others will share the same view. Thanks very much.


manojglobal profile image

manojglobal 4 years ago from Kolkata


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

You are welcome. I am glad you appreciate the information.


Aitorman 4 years ago

Great article! thanks


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Thanks Aitorman! I hope you find it useful.


icarr4077 4 years ago

Hey, love your tutorials but I am having some issues. Tried working this into an app that I am working on but it created some errors that I am trying to work out. Just to see it work I copied your coding and paste it into a new project and it still kicked back some errors, not sure what's wrong, any advice? Here is the error:

2012-04-12 16:22:57.801 SaveLoad[22295:f803] Error writing file at /Users/Ian/Library/Application Support/iPhone Simulator/5.1/Applications/55BD1DB2-D85B-425C-AB79-6CE0E3186407/Documents/mytextfile.txt

(null)

This is from your code verbatim, literally copied everything. Running on xCode 4.3.2 and using the iPod simulator for this project.


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Hi icarr, Sorry to hear you are having problems. It would seem like your string variable is null or not set properly. Your path is set properly. I will pull out the code and try to see I forgot to include some part of the app in the tutorial.


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

I might only be able to get back to you this evening (EST) hope this is ok. Sorry you have are having probs.

Kevin


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Hi icarr, I have run my project and I am getting absolutely no errors writing and reading from app. If you can send me your e-mail I can send you the projet code. Are your delegates set properly?

Kevin


Haider Ali 4 years ago

Hi,very good tutorial


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Thanks


tdp 4 years ago

How would I implement this for an image?


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

You can use the Quartz and Cocoa2d api to create images which can either be saved as pdf or as an image file. I don't have any code examples.


mttctr 4 years ago

Hi, great tutorial, well explained. One thing I'm not sure about is why you created the 'Files' group at the start when you don't appear to save anything to it, as directory location is 'Documents'?


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

The groups in Xcode are only like labels in the project. They don't serve any other purpose in the actual app. Open the project through Finder and you will see that groups don't have a physical location. Thanks for the feedback.


Jane 3 years ago

Hello, Kevin!

Very useful and helpful tutorial!

I make one interesting project on iOS and I'm very happy that I have found your example for write /read to a file. Very good lesson. Thanks!

Jane.


klanguedoc profile image

klanguedoc 3 years ago from Canada Author

Thanks


Inder 2 years ago

Thank You very much! Very helpful and well explained code.


klanguedoc profile image

klanguedoc 2 years ago from Canada Author

Thanks


Lucky 2 weeks ago

Thank you.....very much....

    Sign in or sign up and post using a HubPages Network account.

    0 of 8192 characters used
    Post Comment

    No HTML is allowed in comments, but URLs will be hyperlinked. Comments are not for promoting your articles or other sites.


    klanguedoc profile image

    Kevin Languedoc (klanguedoc)323 Followers
    144 Articles

    Kevin is Software Developer with 20 years experience designing and building software applications including iOS and Android apps.



    Click to Rate This Article

    Menu

    Explore