I have an NSMutableArray of Strings. The Strings in the array, are converted from dates to Strings and I need to sort them and show them in a tableview.
I need:
June 24, 2011
June 26, 2011
July 1, 2011
And so on.
I know questions similar to this have been asked, but I didn´t get it to work. So I would really appreciate if someone could help me!
Sort them while they're still dates, keep them as a sorted list of dates, and only format them as text as needed for display (i.e., during -tableView:cellForIndexPath:).
Alternatively, the ISO 8601 date formats (an example formatted date would be 20110603T1345.123-4) mostly sort lexicographically the same as they would as dates. Times in different time zones or that cross a summer time shift can invalidate this property, though, so leaving dates as dates would still be your best bet.
Easy way to do this is to create a function of the form
NSInteger funcName(id left, id right, void* extra);
you can then use NSMutableArray's sortUsingFunction:context: passing your comparison function in. Jeremy is correct in stating that dates are easier to sort, they have built in comparison functions:
– isEqualToDate:
– earlierDate:
– laterDate:
– compare:
See NSMutableArray for sorting information and NSDate for its comparison methods
Your NSMuatbleArray must have the NSDate object.
First you need to sort the array using -[NSMutableArray sortUsingSelector:] and need to pass #selector(compare:).
The compare: function of NSDate will do the job for you and sort the array in ascending order ..
After following the above you just need to call reloadData function of UITableView.
Related
I have NSStrings that represent times of the format mm:ss.SSS in my app. I am trying to generate a list of "fastest times" and I'm struggling trying to figure out what data types to use to order these numbers.
What is the easiest way to order these strings from least to greatest amount of time? I'm assuming converting to a numbered data type would do the trick, but what data type should I be using? I need to preserve the mm:ss.SSS formatting.
If you have NSString objects you can convert to NSDate objects (such as these, presumably, which you could, for example, convert into ISO 8601 format using a suitable offset), then you can sort an NSArray instance of NSDate objects very easily (example) and pick from the top or bottom of the list, depending on whether you sort in descending or ascending order.
The advantage of this approach is that you are working with standard date processing functions, which can result in less code and less debugging. Reinventing the wheel may get you a faster solution, but it can also introduce bugs.
You can also use (abuse ?) localizedStandardCompare: for that purpose, because that method compares numbers embedded in the string according to their numerical value:
NSArray *times = #[ #"11:22.333", #"2:44.555" ];
NSArray *sortedTimes = [times sortedArrayUsingSelector:#selector(localizedStandardCompare:)];
NSLog(#"%#", sortedTimes);
Output:
(
"2:44.555",
"11:22.333"
)
If the strings are well-formed, with leading zeros, form an NSArray and then invoke sortedArrayUsingComparator:. But if you have values like 12:34.567 and 2:34.567, this approach won't work. You'll have to convert, either to double or NSNumber, storing seconds (that is, 2:34.567 converts to 154.567).
Note that these are not NSDate objects. An NSDate marks a particular instant in time, and these appear to be simply durations.
If you use NSNumber, you can still use sortedArrayUsingComparator:. You'll have to write a subclass of NSFormatter, to convert between mm:ss.SSS and NSNumber and back again.
See the documentation for NSComparator for a blocks-based example. You'll also need the Class Reference for NSFormatter. The FormatterKit project on GitHub has some nice NSFormatter sample code.
My advice is to create your own class that represents the datatype for mm, ss and SSS. You can then write your own prettyprint and compare methods for the datatype. The compare method itself would be fairly simple to implement and you can then use that compare method to sort an array of such objects.
I have some objective-c code I'm converting from iPhone to iPad. CFGregorianDate is used throughout for date functions. I have never used it, preferring to use NSDate.
I want to take the date and format it so I get the full month name, using the format string "MMMM", which I don't seem to be able to do using CFGregorianDate.
What's the difference between the two, and does it make any difference in usage?
From the docs:
CFDate is “toll-free bridged” with its Cocoa Foundation counterpart, NSDate. What this means is that the Core Foundation type is interchangeable in function or method calls with the bridged Foundation object. In other words, in a method where you see an NSDate * parameter, you can pass in a CFDateRef, and in a function where you see a CFDateRef parameter, you can pass in an NSDate instance. This also applies to concrete subclasses of NSDate.
So, no difference in usage, really. The main difference is that CFDate and its subclasses are legacy types.
However, as has been pointed out, CFGregorianDate is extremely different from CFDate. It doesn't store a timestamp but rather the year, month, day, hour minute and second as separate integers.
So your best bet is to create a method like cfGregorianToNSDate: in which you parse these integers and construe a new NSDate object.
currently, i am working on an app that uses Core Data. One of my managed objects has a property that keeps track of the day of week (Sunday - Saturday) as an integer (0-6). For the sake of sorting the objects by day as well as less overhead in saving, i definitely believe the best practice is to save the days as indexes and then convert to string during runtime. The question becomes the best practice to convert the index to its corresponding day as a string. ie. 0=>#"Sunday" and 6 => #"Saturday". I can obviously use NSCalendar and NSDate and NSDateComponents to achieve this. It just seems like a very roundabout way to go about it given the simplicity of the task. Naturally, a simple NSString array defined as such could do the trick:
NSString *dayOfWeek[7] = {#"Sunday",#"Monday",#"Tuesday",#"Wednesday",#"Thursday",#"Friday'"#"Saturday"};
But then i find myself constantly redefining this same variable over and over again. A global constant NSString could work. Another idea I had was creating a function that used this dayOfWeek array and then including it in the files that need it. What do you think. What's the best practice?
How about one of the weekdaySymbols methods of NSDateFormatter?
Another solution would be to define a category method on NSString, for example, to return the string based on the number. Then the strings array can be static and only used in that method.
I'm getting a date from a webservice back in the form MM00yyyy -- it is just the two-digit month, followed by two 0's, and then the four-digit year. When I do this:
NSString *expDate = #"12001975";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MM00yyyy"];
NSDate postDate = [dateFormat dateFromString:expDate];
[dateFormat dateFromString] returns nil for some reason. I have also tried MMddyyyy, and MM'0''0'yyyy, with no success either way. I am converting a similar date, except the 0's are actually the day with no problem using the same method.
To get this working, I would just use the following pattern MMHHyyyy. Since you need only the date and not neccessarily the hour, the HH will use the 00 to set the time as zeroth hour and hence you will get the date that you are looking for. Again this is just a hack and a workaround only to solve your current problem.
Have a look at the Date Formatting Guide from Apple. The section "Use Format Strings to Specify Custom Formats" lists all the different standards the are supported by various iOS versions for specifying a format string. I would say that "00" is not allowed, so that is the reason why "MM00yyyy" is failing. Similarly, "MMddyyyy" is also failing because no day can be "00".
I don't know if you can have more luck with UNIX functions, as the Apple doc suggests:
For date and times in a fixed, unlocalized format, that are always guaranteed to use the same calendar, it may sometimes be easier and more efficient to use the standard C library functions strptime_l and strftime_l.
Be aware that the C library also has the idea of a current locale. To guarantee a fixed date format, you should pass NULL as the loc parameter of these routines. This causes them to use the POSIX locale (also known as the C locale), which is equivalent to Cocoa's en_US_POSIX locale, as illustrated in this example.
struct tm sometime;
const char *formatString = "%Y-%m-%d %H:%M:%S %z";
(void) strptime_l("2005-07-01 12:00:00 -0700", formatString, &sometime, NULL);
NSLog(#"NSDate is %#", [NSDate dateWithTimeIntervalSince1970: mktime(&sometime)]);
// Output: NSDate is 2005-07-01 12:00:00 -0700
Getting the format strings right seems much more like art than science. I suggest you make a new string without the 00 in it and then have your DateFromatter process that with "MMyyyy".
While this might not be the "correct" way to do it, it should solve your problem pretty quickly.
The zeros are unsupported symbols. Apple supports the following characters for date formatting: http://unicode.org/reports/tr35/tr35-10.html#Date_Format_Patterns See the day section.
The subject is vague because I'm not sure how to articulate in one sentence what I want.
Here goes:
I have an NSArray of NSDictionaries. Each NSDictionary represents one day of the calendar year. Each NSDictionary has a key "date" with a value of NSDate. There should be 365 NSDictionary items in the array. The dictionary is created by a server that I don't control, and it sometimes is missing as many as 100 days.
I need to ensure the array has 365 dictionaries, each one day later than the next.
I currently sort the array by date, iterate through it, copying the NSDictionaries from the current array to a new array. While so doing, I compare the current Dictionary's date value with the date value for the next dictionary. If there is more than one day between the two dates, I add enough new dictionaries to the new array to cover those missing days (and set their dates accordingly), then continue through.
Since the dates are supposed to ordered, I wonder if there is not already a mechanism in the framework or language that I can use to say "Here is an array, and this keypath is supposed to be consecutive. Find and create the elements that are missing, and here's a block or method you can use to initialize them".
Something about my method just feels poorly implemented, so I turn to you. Thoughts?
Thanks.
The way you did it sounds perfectly sane, and there is nothing to my knowledge that will do it automatically in the base framework.
This code will sort them.
NSArray *dates; // wherever you get this...
NSArray *sortedDates = [dates sortedArrayUsingComparator:^(id obj1, id obj2)
{
return [[obj1 valueForKey:#"date"] compare:[obj2 valueForKey:#"date"]];
}];
As for creating the missing entries, you'll have to do that yourself.
You don't need to do the sort:
Create an array with 365 (or 366) placeholder dictionaries (you can possibly use the same one for all slots, or use NSNull)
iterate through the passed in array and figure out which day each of the dictionaries is for. Place each dictionary in its rightful slot in your array.