iPhone: Reading Text From File and UISegmentedControl - iphone

First off, I'm a complete beginner.
That said, I thought an ambitious longer-term project/learning experience would be to create an app that displayed daily quotes, like those cheesy day-by-day calendars our grandmothers have in their bathrooms. I want it to have two per day, each one represented by a tab in a UISegmentedControl. That's the long term. Right now I'd be happy with getting a single day's worth of quotes functioning.
Onto the questions:
How can I get text saved in a .txt or .rtf file to be displayed in a UITextView? Preferably without using 'stringWithContentsOfFile,' since Xcode is telling me that's deprecated.
How can I get content from a different file (or maybe a different portion of the same file...?) to be displayed when the user taps the second segment?
If I can get it running so that those two conditions are met and I understand what's going on, I'll consider the day a success. Thanks!

1.
NSError *error = nil;
NSStringEncoding stringEncoding;
NSString *fileText = [NSString stringWithContentsOfFile:#"/path" usedEncoding:&stringEncoding error:&error];
myTextView.text = fileText;
The error and encoding are optional, and you can pass in nil for both. But if you care about the error, or what encoding the file was in they will have useful info in them after the string is created.
2.
Set the valueChanged outlet in Interface Builder to an IBAction on your controller, such as setSegmentValue:. Then, assuming you have an array of quote strings:
- (IBAction)setSegmentValue:(id)sender {
UISegmentedControl *control = (UISegmentedControl*)sender;
NSString *quote = [quotes objectAtIndex:control.selectedSegmentIndex];
myTextView.text = quote;
}

Even though stringWithContentsOfFile: is deprecated, stringWithContentsOfFile:usedEncoding:error: is not. That is the standard method to use for reading from files.
As for the second question, you simply test the state of the segmented control and perform as action based on it. Admittedly this is a high level answer but should get you going.

Related

How To Parse CSV Data

I want to parse CSV data, which is downloaded to the app. Right now I have the following data - "SPY",186.33,"3/17/2014","4:00pm",**+1.67**,185.59,186.77,185.51,93784328. I used NSLog to display it on the console. What I want to do is read the 1.67 (or whatever it may be) and turn it into an NSString. The url where I get the information from will be consistent, but the numbers will change day to day. Thanks in advance!
If you're able to capture the row of data as a string (which it sounds like you've done, since you're able to NSLog it to the console), then you should be able to split the string apart like so:
NSArray *stringComponents = [yourDataRow componentsSeparatedByString:#","];
NSString *desiredComponent = [stringComponents objectAtIndex:4];
Then, your +1.67 (or whatever) will be available as desiredComponent.
Note: This solution assumes that the +1.67 component of the row will always occupy the 5th position in the row.
I use CHCSVParser by Dave DeLong, it supports parsing this format from a file, NSString, or NSInputStream. Probably your best bet! https://github.com/davedelong/CHCSVParser

How to open unzip files in a unique folder each time on iOS

On my iOS application I'm unziping files in "app/temp" folder like this:
NSString *unzipFolder = [[CommonFunctions getCachePath] stringByAppendingPathComponent:#"/temp/"];
and once im done with it im deleting item with:
[[NSFileManager defaultManager] removeItemAtPath:unzipFolder error:&e];
Issue is that bcz im creating mulital copy of unzip files some of the files Images name are same and displaying wrong images, and i dont find error on why my deleting function does not work!
IS there any way that i can do unziping of folder on diffrent path for each message that open by user?
Thanks :)
It sounds like all you're asking is how to generate a unique name for your unzipFolder each time.
Just don't use a hardcoded name. Almost anything will do. For example:
NSString *unzipFolderTemplate = [[CommonFunctions getCachePath] stringByAppendingPathComponent:#"temp.XXXXXX"];
char *template = strdup([template fileSystemRepresentation]);
if (mkdtemp(template)) {
NSString *unzipFolder = [NSString stringWithFileSystemRepresentation:template
length:strlen(template)];
free(template);
// do the work
[[NSFileManager defaultManager] removeItemAtPath:unzipFolder error:&e];
}
The nice thing about mkdtemp is that it creates the directory for you, and guarantees there are no race conditions, somehow-left-over directories, or other problems. It's also more secure against, say, someone writing a crack or other jailbreak hack that exploits your code by predicting the path. The downside is, of course, that you have to drop down to C strings (which means an explicit free). But, as I said, there are many possibilities, and almost anything will do.
Also, note that I'm using #"temp.XXXXXX", not #"/temp.XXXXXX/". That's because -[stringByAppendingPathComponent:] already adds any necessary slashes for you (that is, in fact, the whole point of the method), and directory-creation functions don't need a trailing slash, so both of the slashes are unnecessary.
Meanwhile, I'm still a bit confused by what you're trying to do. If you need to keep a unique folder around for each message, and delete the folder when you're done with that message, and you could have multiple messages open at once, you need some way to remember which folder goes with which message.
For that, create an NSMutableDictionary somewhere, and right after the free(template) you'll want to do something like [tempFolderMap addObject:unzipFolder forKey:messageName]. Then, when closing a message, you'll do [tempFolderMap objectForKey:messageName] and use the result to the removeItemAtPath:error: message (and then you can also remove the key from tempFolderMap).

Loading text from a file

I am making an Iphone drinking card game app.
All the card mean something different and i want the user to be able to press an info button and then show a new screen with information about the current card. How can i make a document to load text from instead of using a bunch og long strings?
Thanks
You could look into plist files - they can be loaded quite easily into the various collection objects and edited with the plist editor in Xcode.
For instance, if you organize your data as a dictionary, the convenience constructor
+ (id)dictionaryWithContentsOfURL:(NSURL *)aURL
from NSDictionary would provide you with as many easily accessible strings as you need.
This method is useful if you consider your strings primarily data as opposed to UI elements.
Update:
As #Alex Nichol suggested, here is how you can do it in practice:
To create a plist file:
In your Xcode project, for instance in the Supporting Files group, select New File > Resource > Property List
You can save the file in en.lproj, to aid in localization
In the Property list editing pane, select Add Row (or just hit return)
Enter a key name (for instance user1) and a value (for instance "Joe")
To read the contents:
NSURL *plistURL = [[NSBundle mainBundle] URLForResource:#"Property List" withExtension:#"plist"];
NSLog(#"URL: %#", plistURL);
NSDictionary *strings = [NSDictionary dictionaryWithContentsOfURL:plistURL];
NSString *user1 = [strings objectForKey:#"user1"];
NSLog(#"User 1: %#", user1);
A plist, a JSON string, and an SQLite database walked into a bar ...
Oops!! I mean those are the three most obvious alternatives. The JSON string is probably the easiest to create and "transport", though it's most practical to load the entire thing into an NSDictionary and/or NSArray, vs read from the file as each string is accessed.
The SQLite DB is the most general, and most speed/storage efficient for a very large number (thousands) of strings, but it takes some effort to set it up.
In my other answer, I suggest the use of a dictionary if your texts are mostly to be considered as data. However, if your strings are UI elements (alert texts, window titles, etc.) you might want to look into strings files and NSBundle's support for them.
Strings files are ideally suited for localization, the format is explained here.
To read them into you app, use something like this:
NSString *text1 = NSLocalizedStringFromTable(#"TEXT1", #"myStringsFile", #"Comment");
If you call your file Localizable.strings, you can even use a simpler form:
NSString *str1 = NSLocalizedString(#"String1", #"Comment on String1");
A useful discussion here - a bit old, but still useful.

iphone sql - data corrupted/ missing when reading

I'm using SQL to store data in my application. I read data in the app delegate and store it in an array like so.
(First I read from the database and store in aFlashcardSet and then this)
// Add the flashcardSet to the main Array
[mainSetsArray addObject:aFlashcardSet];
In my next view I then copy the data from the app delegate.
flashcardsAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
self.setsArray = delegate.mainSetsArray;
Then I pass one object from the set to the final view.
cardDetailViewController.thisCardSet = [setsArray objectAtIndex:row];
The problem is when I read the data in the final view and use to set UI elements the app crashes, the code works fine with data hard coded during the second phase and the database data is shown fine during the second phase (to populate a table view). I've tried outputting the data at all stages and it is all correct until the final view where it either crashes or shows incorrect values (file names or random letters rather than the actual text).
I have also tried to read the database data inside the final view and set it to thisCardSet but it still suffers the same problem.
Any ideas?
Thanks.
The problem was inside one of my custom classes I wasn't using self, so I was writing.
aString = string;
Rather than -
self.aString = string;
So I was losing data down the line, feel really stupid but hope it help's someone else =].

USe NSCoding To Create User Editable Plist

I'm trying to create a user editable plist where the user can store a custom created workout routine including strings referenced from another data.plist in the app bundle.
I'm assuming NSCoding is the best way to go about this. So far I have the interface setup as a nav bar and table view.
I want it to be blank be default and the user has to press the "+" that is in the top right of the nav bar. Then he could enter a name for an entry in an array, for example chest day, or bicep day. And within that array, will be a dictionary or another array of strings of the particular exercises for that day, for example bench press, or bicep curl.
This plist needs to be editable so it will be going in the users document folder and not in the app bundle.
Example:
Top array consists of Chest Day, Back Day, Leg Day. Within Chest Day dictionary, include bench press, chest pull, pushup, etc.
Update:
Adding this method to search for routine file;
-(void)loadData
{
if(YES)
{
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* routineFile = [documentsPath stringByAppendingPathComponent:#"routine.plist"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:routineFile];
}
else
{
//load file
}
}
NSCoding is the protocol used by NSArchiver, NSKeyedArchiver, etc., not for serializing an array into a property list.
Forget about the idea that the user is going to edit a property list. The user is going to edit data in your app -- the fact that it's stored as a property list is just an implementation detail. When your app starts, you read the data stored in the data file. The user edits it, looks at it, whatever. At some point later, perhaps after each edit, perhaps just before the app quits, you write the data back out to the file. Since it's a property list, don't worry about updating the file; you already have all the data, so write a whole new property list and then use that file to replace the old one.
Perhaps I'm wrong and you really do intend for the user to edit the property list by hand, with a text editor. This would be a mistake. It's great the property lists are human readable, but asking your users to edit your raw data files by hand is a strong indication that your app is broken. The whole purpose of your app is to keep track of this information for the user; if they wanted to use a text editor to manage it, they wouldn't need your app. So, with that said, I hope I'm not wrong. ;-)
I don't think I'd use NSCoding for this - if all you're working with is standard plist objects like NSArray, NSDictionary, and NSString, the top array's -writeToFile:atomically: method is an easy way to do the job.