What's the difference between NSDate and CFGregorianDate? - objective-c

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.

Related

Understanding ObjC bad message examples?

I'm currently reading The Big Nerd Ranch Guide on Objective C programming and I'm having trouble understanding a section in Chapter 13, Objects which is providing bad examples of Messages:
NSDate *now = [NSDate date];
double seconds = [now timeIntervalSince1970];
This is firstly a correct example of using messages in Objc. The first line creates a pointer to an NSDate object using the variable now and the NSDate type declaration. It is now an instance of NSDate. It was explained to me that if you are to print now, it will display the output of the NSDate date method. This is where things start to get a little weird for me. It seems odd that you would have a variable pointing both to an instance, and a function output if printed. But that's okay. Moving on.
The second line creates a variable called seconds, which is of type "double" and is going to obtain a value that the timeIntervalSince1970 method of NSDate instance now outputs.
Here is where the author introduces examples of bad messages:
double testSeconds = [NSDate timeIntervalSince1970];
NSDate *testNow = [now date];
He explains the errors as follows:
First Line:
"The Error is clear, the receiver in this message send is the NSDate
class, so the selector should be the name of an NSDate class method.
This selector is not."
Ok. This makes sense. An invalid method. Next. .
Second Line:
"This error is less clear: It is telling you that NSDate has no
instance method whose name matches the date selector."
Wait, what? Isn't now a pointer to an instance of NSDate? Shouldn't you be able to call the date method from an instance of NSDate? I don't get it.
The book does not explain any more than what I've quoted above, so I'm sure it's something stupid and basic I'm not getting. I hope this isn't too specific or unhelpful to others. I'll delete the submission if asked. Thank you.
The variable now points to an instance of NSDate. The method date is not defined on instances of NSDate but on the class itself. Hence date is a class method and not an instance method. Unlike other programming languages Objective-C does not inherit class methods to their class instances.
Vice versa instance methods cannot be called on classes. This said timeIntervalSince1970 cannot be called on the class NSDate as this method is an instance method. This is due to the circumstances that instances usually manage an instance state. Instance methods do operate on this instance state, namely reading and modifying their instance variables. Back to your example: The instance method timeIntervalSince1970 calculates the difference between 01/01/1970 and a concrete, instantiated date. So if you would be able to call timeIntervalSince1970 on class level there's no chance to calculate a difference of dates as the class NSDate doesn't carry any date information (the instance state!) such as the day, month, year and the time.
To sum up: Instance methods cannot be called on classes. This isn't supported by any programing language I am aware of. Calling class methods on instances is however supported by some programing language although there's typically no need for doing so and sometimes it even lowers code readability. However Objective-C doesn't support those calls neither.

Ordering NSStrings that are numbers of a particular format (ex 3:23.123)?

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.

How is an NSNumber represented on disk?

Not sure why Objective-C decided to use NSNumber instead of float, double, etc. How is this type represented on disk?
NSNumber is toll-free bridged with CFNumber. In recent implementations of Core Foundation, CFNumber is a tagged pointer. This lets it be treated as an object, but without all the overhead of an object. Instead, the value is encoded in the object pointer (and isn't actually a pointer).
See Tagged pointers and fast-pathed CFNumber integers in Lion.
NSNumber is a descendant of NSObject, so it can go wherever an id can go: NSarray, NSDictionary, and so on. Primitives such as int and double cannot go in these classes, because they do not inherit from NSObject, and hence cannot participate in collections etc.
If I were to guess on the internals of NSNumber. I'd say it's a union and a type selector field. However, the beauty of encapsulation lets me successfully program to NSNumber without knowing a first thing about its representation (and not missing that knowledge).
One thing to keep in mind is that Objective-C is a super-set of C, so they didn't decide to use NSNumber instead of the primitive types (float, double, etc.) but in addition to them. If you don't need the functionality of NSNumber, then just use the primitive types and save the overhead of creating/destroying the objects. Many functions in iOS (notably the array type functions) only work with objects (descendants of NSObject). Therefore, if you want to pass some type of number to one of these functions, you need an object representation of it. This is where NSNumber comes in.
To quote the documentation on NSNumber:
NSNumber is a subclass of NSValue that offers a value as any C scalar
(numeric) type. It defines a set of methods specifically for setting
and accessing the value as a signed or unsigned char, short int, int,
long int, long long int, float, or double or as a BOOL. (Note that
number objects do not necessarily preserve the type they are created
with.) It also defines a compare: method to determine the ordering of
two NSNumber objects.
Note that internally the actual value is stored either as an integer or as a floating point number (within either a tagged pointer as Jay describes or a union in an object), depending on what value you are storing. This is important to know as if you try to store a number like "32.1" it will store it as a floating point number and when you retrieve it you will most likely get something like "32.09999999999999".
As far as storing it to disk, if you need to do this then you typically store it with encodeWithCoder and retrieve it with initWithEncoder which converts it to a format intended to be saved to disk and later read back in.

converting day of week index to string objective c

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.

Sort array with string dates Objective C

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.