How to create read/write .txt file in xcode4? [closed] - ios

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
i am newbie of iOS development , i'm facing a problem from last 2 days
I want to create , read and write .txt file in xcode4 ... please help me as a complete code.
your answer accepted warmly.
Thanks.

For each iOS app you can only write file inside app's document directory.
Here is a sample code to do that.
//ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
#public
NSString *filePath;
NSString *fileData;
IBOutlet UITextView *textView;
}
#property (nonatomic, retain) NSString *filePath;
#property (nonatomic, retain) NSString *fileData;
#end
//ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize filePath;
#synthesize fileData;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [[NSString alloc] initWithFormat:#"%#", [paths objectAtIndex:0]];
//define a file path
filePath = [[NSString alloc] initWithFormat:#"%#", [documentsDirectory stringByAppendingPathComponent:#"YourFile.txt"]];
//check if file is exists or not then write some data
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:filePath])
{
fileData = #"My name is maverick";
[fileData writeToFile:filePath atomically:YES encoding:NSUnicodeStringEncoding error:nil];
textView.text = fileData;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)readFile:(id)sender
{
fileData = [[NSString alloc] initWithContentsOfFile:filePath usedEncoding:nil error:nil];
textView.text = fileData;
}
-(IBAction)writeFile:(id)sender
{
fileData = textView.text;
[fileData writeToFile:filePath atomically:YES encoding:NSUnicodeStringEncoding error:nil];
}
#end

Related

string = textView.text, yet string is (nul)

I've literally tried everything. I'm sure my mistake is going to be something as stupid and small as a missed self.string, but I can't seem to get it working. What my mini program does is checks if a file named Code.txt already exists. If it does exist, then it will load the file in a UITextView (and it does this just fine). If it doesn't exist, it will create a file name Code.txt. All of this works just fine.
However, when I try to save the current text inside the UITextView to the file, I am unable to save it to the string first. This is what I am trying to achieve:
Upon exiting the app: textView.text --> codeString --> Code.txt [saved]
Except, again, I am unable to save the textView.text to the string (codeString). The NSLog is returning it as a nut (see NSLog(#"String: %#", self.codeString); in the saveFile method).
ViewController.h
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "BuildViewController.h"
#interface ViewController : UIViewController <UITextViewDelegate>
#property (nonatomic, strong) NSString *codeString;
#property (nonatomic, retain) IBOutlet UITextView *textView;
#property (nonatomic, retain) BuildViewController *buildViewController;
- (void)saveFile;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize textView;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
textView.delegate = self;
// Check if Code.txt exists
NSString* documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *codeFile = [NSString stringWithFormat:#"%#/Code.txt", documentsDir];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:codeFile];
NSLog(#"viewWillAppear");
if (fileExists == true) {
// Code.txt does exist, continue to viewDidLoad
NSLog(#"Code.txt does exist");
}
else if (fileExists == false) {
// Code.txt does not exist, create the file
NSLog(#"Code.txt does not exist");
ViewController *viewController = [ViewController alloc];
[viewController createFile];
}
self.textView.delegate = self;
}
- (void)viewWillAppear:(BOOL)animated {
// Load Code.txt
NSString* documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* codeFile = [documentsDir stringByAppendingPathComponent:#"Code.txt"];
NSString *codeString = [NSString stringWithContentsOfFile:codeFile encoding:NSUTF8StringEncoding error:NULL];
textView.text = codeString;
NSLog(#"Loaded Code.txt");
}
- (void)saveFile {
// Save text to Code.txt
self.codeString = textView.text;
NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *codeFile = [NSString stringWithFormat:#"%#/Code.txt", documentsDir];
[self.codeString writeToFile:codeFile
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
NSLog(#"String: %#", self.codeString);
NSLog(#"Saved text to Code.txt");
}
- (void)createFile {
NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *codeFile = [NSString stringWithFormat:#"%#/Code.txt", documentsDir];
NSString *codeString = #"print(\"Hello, world\")";
[codeString writeToFile:codeFile
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
NSLog(#"Created Code.txt");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Your error is you create a new instance of ViewController like #Avi said.
You should get the existing instance in memory
If you want to save file when in background,you may register notification
In viewDidLoad,add this line
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
Then add this function to ViewController
-(void)enterBackground:(NSNotification *)notification{
[self saveFile];
}
Then in dealloc
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}

Writing and reading custom object to file IOS

i have this object.
#interface SeccionItem : NSObject <NSCoding>
{
NSString * title;
NSString * texto;
NSArray * images;
}
#property (nonatomic,strong) NSString * title;
#property (nonatomic,strong) NSString * texto;
#property (nonatomic,strong) NSArray * images;
#end
With this implementation
#implementation SeccionItem
#synthesize title,texto,images;
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:title forKey:#"title"];
[encoder encodeObject:texto forKey:#"texto"];
[encoder encodeObject:images forKey:#"images"];
}
- (id)initWithCoder:(NSCoder *)decoder {
title = [decoder decodeObjectForKey:#"title"];
texto = [decoder decodeObjectForKey:#"texto"];
images = [decoder decodeObjectForKey:#"images"];
return self;
}
#end
I want to save an array filled with this objects to a file on disk.
Im doing this:
to write
[NSKeyedArchiver archiveRootObject:arr toFile:file];
to read
NSArray *entries = [NSKeyedUnarchiver unarchiveObjectWithFile:name];
return entries;
But the readed array is always empty, i dont know why, i have some questions.
What format should i use for file path? on toFile:?
The NSArray on the object is filled with NSData objects, so i can encode them?
Im really lost on this.
Take a look at the documentation of NSKeyedArchiver, especially the archiveWithRootObject:toFile: method.
The path is basically where the file should be stored including the file name. For example you can store your array in your app Documents folder with file name called Storage. The code snippet below is quite common:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex: 0];
NSString* docFile = [docDir stringByAppendingPathComponent: #"Storage"];
The method NSSearchPathForDirectoriesInDomains is used instead of absolute path because Apple can be changing the Documents folder path as they want it.
You can use the docFile string above to be supplied to the toFile parameter of the archiveWithRootObject:toFile: method.
Use the following method to save data
-(NSString*)saveFilePath {
NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *pathString = [[pathArray objectAtIndex:0] stringByAppendingPathComponent:#"data"];
//NSString *pathString = [[NSBundle mainBundle]pathForResource:#"Profile" ofType:#"plist"];
return pathString;
}
-(void)saveProfile {
SeccionItem *data = [[SeccionItem alloc]init]
data. title = #"title";
data. texto = #"fdgdf";
data.images = [NSArray arrayWithObjects:#"dfds", nil];
NSMutableData *pData = [[NSMutableData alloc]init];
NSString *path = [self saveFilePath];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:pData];
[data encodeWithCoder:archiver];
[archiver finishEncoding];
[pData writeToFile:path atomically:YES];
}
Use the following method to load data
-(void)loadData {
NSString* path = [self saveFilePath];
//NSLog(path);
NSMutableData *pData = [[NSMutableData alloc]initWithContentsOfFile:path];
NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:pData];
data = [[SeccionItem alloc]initWithCoder:unArchiver];
//NSLog(#"%#",data.firstName);
[unArchiver finishDecoding];
}
For those who are seeking the solution in swift, I was able to write and read dictionary to file system as follows :
Write:
let data = NSKeyedArchiver.archivedData(withRootObject: dictionary)
do {
try data.write(to: destinationPath)
} catch let error {
print("\(error.localizedDescription)")
}
Read:
do
{
let data = try Data.init(contentsOf: path)
// path e.g. file:///private/var/ .... /Documents/folder/filename
if let dict = NSKeyedUnarchiver.unarchiveObject(with: data){
return dict
}
}
catch let error
{
print("\(error.localizedDescription)")
}

IOS and .plists

I am working on an app for a Senior Capstone and I am working with .plist for the first time. What I have so far is in my .h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
-(NSString *)dataFilePath;
-(IBAction) readPlist:(id)sender;
-(IBAction) writePlist:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *textBox;
#end
and in my .m I have:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSString *) dataFilePath
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES );
NSString *documentDirectory = [path objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"JoesData.plist"];
}
- (IBAction)readPlist:(id)sender
{
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
NSLog(#"%#\n",array);
NSLog(#"%#\n", filePath);
}
}
- (IBAction)writePlist:(id)sender {
NSString *string = _textBox.text;
NSMutableArray *anArray = [[NSMutableArray alloc] init];
[anArray addObject:string];
[anArray writeToFile:[self dataFilePath] atomically:YES];
}
#end
so what this does is creates a .plist based upon what is in the text box that I have set up in my storyboard. My problem with this is that it will read and write it just fine, but it won't keep a running list of the things that are entered into the text box. Instead, it simply overwrites the previous .plist. Any thoughts on how to fix the overwriting problem?
Read the plist into memory, make a mutable copy of the array, and add the object to that array, instead of creating a new NSMutableArray every time.
An alternative option is to do the following.
To read the property-list data back into your program, first initialize an allocated NSData object by invoking initWithContentsOfFile: or initWithContentsOfURL: or call a corresponding class factory method such as dataWithContentsOfFile:. Then call the propertyListFromData:mutabilityOption:format:errorDescription: class method of NSPropertyListSerialization, passing in the data object.
Property List Programming Guide

Load data SQlite into htmlString iOS

I have an app that reads from sqlite database,data is read and included in the objects using this method ....I checked with NSLog
#import "ViewController1.h"
#import "Ricetta.h"
#import "AppDelegate.h"
static sqlite3_stmt *leggiStatement = nil;
#interface ViewController1 ()
#end
#implementation ViewController1
#synthesize Webmain, oggetto2;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//percorso file su cartella documents
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *path = [documentsDir stringByAppendingPathComponent:#"Rice.sqlite"];
//controllo se il file esiste
if(![[NSFileManager defaultManager] fileExistsAtPath:path])
{
//se non esiste lo copio nella cartella documenti
NSString *pathLocale=[[NSBundle mainBundle] pathForResource:#"Rice" ofType:#"sqlite"];
if ([[NSFileManager defaultManager] copyItemAtPath:pathLocale toPath:path error:nil] == YES)
{
NSLog(#"copia eseguita");
}
}
[self personalizzaAspetto];
[self carica_ID];
// NSString * query = #" SELECT Immagine, Titolo, Descrizione FROM LIBRO";
// NSArray * arrayQuery = [[NSArray alloc] initWithObjects:#"Immagine",#"Titolo",#"Descrizione",nil];
// NSArray * arrayElementi = [self caricaValoriMain:query :arrayQuery];
Webmain= [[UIWebView alloc]initWithFrame:CGRectMake(0, 0, 320, 365)];
NSString *htmlString =[NSString stringWithFormat:#"<html> \n"
"<head> \n"
"<style type=\"text/css\"> \n"
"body {font-family: \"%#\"; font-size: %#;}\n"
"</style> \n"
"</head> \n"
"<body><center><img src='%#'/></center></body><center><h1>%#</h1></center><body bgcolor=\"#FFFFFF\" text=\" #ffa500\">%#</body></html>" ,#"futura",[NSNumber numberWithInt:15],oggetto2.Immagine,oggetto2.Titolo,oggetto2.Descrizione];
[Webmain loadHTMLString:htmlString baseURL:nil];
[self.view addSubview:Webmain];
-(void)carica_ID{
sqlite3 *database = NULL;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *dbPath = [documentsDir stringByAppendingPathComponent:#"Rice.sqlite"];
if(sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
if(leggiStatement==nil){
const char *sql = "select Immagine,Titolo,Descrizione from LIBRO WHERE RicettaID=1";
if(sqlite3_prepare_v2(database, sql, -1, &leggiStatement, NULL) != SQLITE_OK)
NSAssert1(0, #"Errore creazione compiledState '%s'", sqlite3_errmsg(database));
}
//while(sqlite3_step(leggiStatement) == SQLITE_ROW)
if(SQLITE_DONE != sqlite3_step(leggiStatement))
{
NSString *titolo = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(leggiStatement, 1)];
NSLog(#"%#",titolo);
oggetto2.Titolo=titolo;
NSString *descrizione = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(leggiStatement, 2)];
NSLog(#"%#",descrizione);
oggetto2.Descrizione = descrizione;
NSString *image= [[NSString alloc]initWithUTF8String:(char *)sqlite3_column_text(leggiStatement, 0)];
NSLog(#"%#",image);
oggetto2.Immagine= image;
}
sqlite3_finalize(leggiStatement);
}
sqlite3_close(database);
}
#end
My problem is that I can not put them in webMain...objects in webMain remain empty.
I do not use Xib.
In the code snippet provided, you never perform the alloc and init of oggetto2. Thus, it is nil, and thus attempts to set its properties will achieve nothing.
In addition to your existing NSLog statements, I'd also suggest doing a NSLog of the htmlString right before you perform loadHTMLString, because it's easier to see what's going on with your HTML by looking at the source, rather than trying to make inferences from a blank web view.
Unrelated to your problem, but you probably should not have code that could potentially reusing your static sqlite3_stmt after you've finalized it. The first time you call carica_ID you would initialize the static leggiStatement. But you end up doing a sqlite_finalize but don't set leggiStatement to nil. If you ever called this method a second time, it won't sqlite3_prepare_v2 again, but you will have freed the resources associated with your prior leggiStatement.
A couple of easy fixes:
do not make leggiStatement a static global, but rather make it a local, non-static variable of the method;
if you do sqlite3_finalize, make sure you set leggiStatement to nil as well; or
don't call sqlite3_finalize, but rather just call sqlite3_reset, which will reset the prepared statement, but won't release its resources.

How do I find the filepath for my plist?

I am trying to load a plist into a UITableView. I am new to working with pLists and tableViews, but I know i need to use something along these lines. My problem is though that where "filePath" is, i don't actually know how to put in my pList?
list = [NSArray arrayWithContentsOfFile:filePath];
Any other suggestions with code how to to do this other than getting the file path would be greatly appreciated. Such as do i need to put anything in my .h file? Thanks.
Assuming you've already added a .plist to your project, I've created a class you can add to your project that will get and save information to a given .plist. It's a functioning singleton, so you can call it from anywhere.
First, create a new NSObject file called "GetAndSaveData", then post the following code into .h:
#interface GetAndSaveData : NSObject{
NSMutableDictionary *allData;
NSString *path;
}
+(GetAndSaveData *)sharedGetAndSave;
-(NSMutableArray *)arrayForKey:(NSString *)dataList;
-(void)setData:(NSMutableArray *)array ForKey:(NSString *)dataList;
#end
and the following code into .m:
static GetAndSaveData *sharedGetAndSave;
#implementation GetAndSaveData
-(id)init{
self = [super init];
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *documentsDirectory = [paths objectAtIndex:0];
path = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error];
}
allData = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
return self;
}
-(NSMutableArray *)arrayForKey:(NSString *)dataList{
NSMutableArray *array = [allData objectForKey:dataList];
return array;
}
-(void)setData:(NSMutableArray *)array ForKey:(NSString *)dataList{
[allData setObject:array forKey:dataList];
[allData writeToFile:path atomically:YES];
if(![allData writeToFile:path atomically:YES])
{
NSLog(#".plist writing was unsuccessful");
}
}
+(GetAndSaveData *)sharedGetAndSave{
if (!sharedGetAndSave) {
sharedGetAndSave = [[GetAndSaveData alloc] init];
}
return sharedGetAndSave;
}
+(id)allocWithZone:(NSZone *)zone{
if (!sharedGetAndSave) {
sharedGetAndSave = [super allocWithZone:zone];
return sharedGetAndSave;
} else {
return nil;
}
}
-(id)copyWithZone:(NSZone *)zone{
return self;
}
#end
You can change the functions up to get and save different types of data. You can use it in view controllers by importing the .h file, and doing the following:
myMutableArray = [[GetAndSaveData sharedGetAndSave]arrayForKey:myKey];

Resources