Sorting is not working correctly - iphone

I am saving some files in document directory through my app using custom naming as "file1.format" ,"file2.format" and so on.Later I fetch these files in an Array and printing them in a loop then they are coming in sorted form but the problem arises when I store "file10.format" and so on. After this the result comes is some what unexpected. As after saving 10th file the output comes like
file1.foramt
file10.format
file2.format
.
.
file6.format
file61.format
file7.format
I don't know why sorting take all 1s or 2s on one place as shown above while it is expected that 10 should just comes after 9 not after 1.I used all kind of sorting but the result is coming same all time.

If you want to sort file names "as the Finder does", use localizedStandardCompare. In particular, numbers in the strings are sorted according to their numeric value:
NSArray *files = [NSArray arrayWithObjects:#"file10.format", #"file2.format", #"file1.format", nil];
NSArray *sorted = [files sortedArrayUsingSelector:#selector(localizedStandardCompare:)];
NSLog(#"%#", sorted);
Output:
2012-11-05 11:38:55.474 test77[533:403] (
"file1.format",
"file2.format",
"file10.format"
)

If you want to go with the regular string sorting sequence, then you should consider renaming your files. file00001.format, file00002.format and so on. In that case file00010.format follows file00009.format and file00011.format comes next

It is actually working correctly.
file10.format
Comes before
file2.format
because the character 0 is seen as less than the character . which it's being compared to (both characters are in the same place in their respective file names.
In fact, back in the day, before you young people with your fancy graphical operating systems, this is how the filesystem sorted files too. </old man rant>

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.

Objective C - Populate Array From Exceedingly large PList

I am having some trouble populating a large plist into an array. Here is the snippet of code giving me problems:
// Populate the routes.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"routes" ofType:#"plist"];
NSMutableArray *routes = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"Routes: %#", routes);
// Populate the trips.
NSString *filePath2 = [[NSBundle mainBundle] pathForResource:#"trips" ofType:#"plist"];
NSMutableArray *trips = [NSMutableArray arrayWithContentsOfFile:filePath2];
NSLog(#"Trips: %#", trips);
My issue is that after displaying each mutable array in the logs, the log for the routes array displays just fine, but the log for the trips array simply doesn't appear at all. Usually when an issue occurs then the log will show something like "Trips: ( )", but that line doesn't appear at all in this case. The only difference I can see between the two instances is that the routes plist is an array with about 1000 dictionary objects and the trips plist has nearly 92,000 objects. Is there some sort of limit on the size of plists?
Thanks in advance.
"Is there some sort of limit on the size of plists?"
There isn't a limit to to the size of plists, but there is a limit to the amount of data that you can feed to an NSLog() command.
If trips were actually nil, the NSLog() call would succeed, and simply print out (null). The trips array is populated, however, which is why it's not printing out at all: NSLog() is saying, "sorry, there's no way I'm going to let you to print out all that".
I believe this has likely changed in more recent versions of OS X due to possible security concerns or performance issues. (In the past, users' hard drives would fill up with log files that were GB in size, caused by one process logging an error message hundreds of times a second; that is now limited to 500 logs per second). It's kind of confusing why nothing is printed out and you get no feedback from Xcode or anything, but I guess the system has no way of knowing whether your use of NSLog() is with good intentions or not.
According to the doc, if there is a parse problem or there is an issue with opening the file, nil will be returned. Is it possible in that massive file there is a bad character or a typo that might break the xml?
"
Return Value -->
An array containing the contents of the file specified by aPath. Returns nil if the file can’t be opened or if the contents of the file can’t be parsed into an array.

For anyone familiar with the "TableViewSuite" sample code in apple dev center

In the "sample code" in iOS Dev Center there is a TableViewSuite.
In the first example SimpleTableView the simulator provides a list of time zones by country.
I can not find the list they are pulling from!
it appears to be an array but I can't find the actual words that are coming up on the simulator screen in Xcode.
I've learned about plists and dictionarys and Arrays and simply can't find where the names are coming from.
I found this line:
// Retrieve the array of known time zone names, then sort the array and pass it to the root view controller.
NSArray *timeZones = [NSTimeZone knownTimeZoneNames];
rootViewController.timeZoneNames = [timeZones sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
Again, where is it retrieving the information from?
Thanks again.
They're coming from this message:
[NSTimeZone knownTimeZoneNames]
Which is documented as such:
Returns an array of strings listing the IDs of all the time zones known to the system.
So essentially they're predefined somewhere in iOS and the names are simply being queried off the system.
+[NSTimeZone knownTimeZoneNames] gets the list of time zones from the system itself. There is no list in the project.