UI blocking when trying to save data in txt file in iOS - ios

I'm trying to save recieving values in Txt file in delegate method using the below code. Those are Integer values, i'm putting those values in graph meanwhile saving in txt file.
but saving values in txt file is blocking graph plotting.
NSError *error;
NSString *filepath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)firstObject] stringByAppendingPathComponent:fileNameString];
NSString *string = [NSString stringWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error:&error];
NSString *writeString = [NSString stringWithFormat:#"%#\n %#",string,values];
[writeString writeToFile:filepath atomically:YES encoding:NSUTF8StringEncoding error:&error];
PS: I used putting this piece of code dispatch_async, then its not saving all receiving values

If you are pushing on a thread and not all the values are being written, it sounds like a race condition with the thread. Try and do all your string processing on the write thread to make sure that thread is the 'source of truth' and has the most updated information.

Related

How do i save multiple strings and not overwrite while writing to a plist file in iOS?

I'm using a "facts.plist" to display a fact(string) after pressing a button, i have a button there that writes that string to a "favourites.txt" file and there i can use it for future use.
Here is the code for that:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [documentsDirectory stringByAppendingPathComponent:#"MyFavorites.txt"];
//documentsDirectory];
[self.displayJoke.text writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
NSError *error;
NSString *str = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%#", str);
But every time I tap that button the previous string gets overwritten with the new string. How do i create a dictionary or Array to prevent this?
every time i tap that button the previous string gets overwritten with the new string
It doesn't "get overwritten". You are overwriting it:
[self.displayJoke.text writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
That line replaces the file fileName with a new file. If that's not what you want to do, then don't do that. If you want to include the existing contents of the file, it's up to you to read the file first and include that in what you write. (Alternatively, you could look into NSFileHandle, which allows you to append to a file.)

Searching data from txt file in iOS

I have a .txt file in which some data is present, when I stored it in an array I got 50000 words. I want to search the data from text file according to user input and show it on UITableview cell, how is it possible ?
Can any body help me?
Here is my code to read data from .txt file in viewDidLoad:
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"myList" ofType:#"txt"];
NSError *error;
NSString *fileContents = [NSString stringWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error:&error];
if (error)
NSLog(#"Error reading file: %#", error.localizedDescription);
// maybe for debugging...
NSLog(#"contents: %#", fileContents);
NSArray *listArray = [fileContents componentsSeparatedByString:#"\n"];
NSLog(#"items = %d", [listArray count]);
You should use fast enumeration using block. Those are fastest of all for loop iteration. But changing the value in that array at time of enumeration could cause a crash.
Here is a link of how to use block enumeration
Here is a link of how it performance wise.
Hope this helps you!!

read/write from a .txt file iOS 7 objc

I have this code:
NSString *studentList = _textIn.text;
NSString *path = [[self applicationDocumentsDirectory].path
stringByAppendingPathComponent:#"ClassOne.txt"];
[studentList writeToFile:path atomically:YES
encoding:NSUTF8StringEncoding error:nil];
NSLog(#"%#", studentList);
NSLog(#"students 1 saved");
I try to write to a text file on the phone system. When I try to read from that file with:
NSError *error;
NSString *strFileContent = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]
pathForResource: #"classOne" ofType: #"txt"] encoding:NSUTF8StringEncoding error:&error];
_textIn.text = strFileContent;
The textfield comes up blank. The NSLog prints what was in the text field but when I try to load it up later the textfield is empty. how do I get the textfield to display what is in the file.
The writing part is alright. You are trying to read the file from your application main bundle instead of your original file path.

How to load app with local data and subsequently update it when online.

Right now I have an app that successfully parses JSON from my website. So whenever there is no internet connection, my app crashes. Now I am trying to make it so that when the app is loaded with no internet connection, it will show the data that was shown previously. What would be the best way to do this?
I read this article but I don't know how to embed a JSON file into my app bundle. Could someone explain how to do this?
Thanks in advance!
The best way is:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"YourParsedJSON.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (noInternet){
if ([fileManager fileExistsAtPath: path]){
// if this is true, you have a saved version of your JSON
YourArray = [[NSMutableArray alloc] initWithContentsOfFile: path];
// or
YourDict = [[NSMutableArray alloc] initWithContentsOfFile: path];
}
else{
// first time the app is running, and no internet, no json, inform user about this
}
}
else{
// make an array or dictionary ( what is your JSON )
// response can be a NSDictionary or NSArray
// YourArray = parsedJSON or YourDict = parsedJSON
[YourArray writeToFile:path atomically:YES];
//or
[YourDictionary writeToFile:path atomically:YES];
}
I hope it helps !
Use Apple Reachability sample code to check if your app is able to establish connection to your server.
On first successful request-response, parse the JSON and cache it to disk as a .plist file. This will save you parsing the stored response again. A parsed JSON response can be a NSDictionary or NSArray. Use the writeToFile:atomically: API to write it to disk.
On subsequent request, if reachability fails, i.e. no network connectivity, read the cached response from disk. You need to decide the cache duration and update the plist when a fresh response is fetched.
Hope that helps!
EDIT:
I think I did not understand the question completely. Thanks Xman, for pointing it out. What I would have done in this case is - save the last loaded JSON file to my bundle and use it for displaying information while querying the server and loading updates in the background.
The flow should be like this:
Parse and display data using local JSON file. (Assuming there is local copy of JSON file)
Query the server for latest data.
Upon receiving response, update the bundle with the latest JSON file.
Then, do step 1. In case there is no JSON file, just start from step 2. If there is a Network error display the appropriate information.
This SO question answers how to handle Network connections in iOS: How to check for an active Internet connection on iOS or OSX?
Saving file locally:
Assuming you have the unparsed JSON data in a NSString (responseString) do the following:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, #"latest_json.json"];
NSError *error;
[jsonString_ writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%#", error)
Reading file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, #"latest_json.json"];
NSString *jsonString_ = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
Previous Answer
Embedding JSON file is similar to embedding any resource into your project. The following method shows you how I added an XML file and accessed it in my app.
Drag and drop your JSON/XML file to your resources group/folder in your XCode window. If you don't have the Resouces folder, it is better you create it. Then in your code do this:
NSString* filePath_ = [[NSBundle mainBundle] pathForResource:#"fileName" ofType:#"json"];
NSString *jsonString = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error: NULL];
the variable jsonstring contails the JSON information. It is upto you how you would like to parse it.

iOS Efficiently Parse Large JSONs from Documents Dir

When I load my app I download around 10-15 JSON files and store them into my apps documents directory-- some range from a few KBs to 30MB.
Once that is finished, I need to grab each of them from the documents dir, convert to a NSDictionary, and parse into NSManagedObjects.
But, when I do that with the code below, as it goes though each JSON it seems to keep them in memory, until the app ends up crashing. Instruments shows nothing in the 'Leaks' tool, but my app is keeping a ton in memory.
Heres the code that grabs the JSON files:
UPDATED
- (void)parseDownloadedFiles
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
docDir = [docDir stringByAppendingString:#"/jsons"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *files = [fileManager contentsOfDirectoryAtPath:docDir error:&error];
if (files == nil) {
// error...
}
for (NSString *file in files)
{
NSString *fileName = [NSString stringWithFormat:#"%#/jsons/%#",
docDir, file];
NSString *content = [[NSString alloc] initWithContentsOfFile:fileName
usedEncoding:nil
error:nil];
NSDictionary *JSON =
[NSJSONSerialization JSONObjectWithData: [content dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
...create my NSManagedObjects & store
JSON = nil;
}
}
--
Heres a look at my allocations:
--
Drilling into that first Malloc 44.79 brings shows me these problem lines:
--
This is within the for loop in the code above
Would that NSLog really cause such an issue?
You should put #autoreleasepool {} inside that loop where you read the file. The objects are not being released until the method returns, so the memory will build up inside the loop.
ARC will help you by autoreleasing the objects but you need them to release faster.
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html
Yep, your getContentFromFile... method is returning a retained string. And you never release it on the receiving end.
You need to either autorelease the string when you return it or explicitly release if after you've parsed it into JSON.
(I'd think Analyzer would have found this.)

Resources