I'm wondering why Apple is using (quite heavily in CoreAnimation, but elsewhere too) constants that are declared as NSString * const
like for example kCAGravityTop
instead of regular enums? How about type safety in this case? As I understand it, one could pass any NSString to a method expecting this constant without getting any compiler warnings.
I'm not sure, but I'm guessing it has to do with users adding their own extensions and subclasses to some of the Apple stuff. In that case, you can just override the used method and catch the case where the string is "MyOwnValue" and then do whatever you want with it. This is significantly easier than having to modify Apple's enum, and it also keeps you from screwing anything up.
It also might be for making it easier for Apple to have version independence. With enums, if you rearrange their order in some way it can cause a lot of problems for any of their values that have been cached (for whatever reason). If the enum's value is 1 << 3 when it is saved to a file, then Apple adds another enum in so that its value is now 1 << 4, then obviously the wrong thing is coming out of your program. Why wouldn't they just be careful about moving enum values around, I don't know, but I think it's definitely likely that they used NSString because there's no way its value or ordering can be changed across any version.
Enumerated types can't be extended without adding additional entries within the enumerated type itself. Thus, it is impossible to have enumeration contents that are both treated both as a formal member of the enumerated type, yet are also not visible during normal compilation.
Take CoreAnimation, for example. There may be values that are used internally that are not supported or made available via the public API for a variety of reasons; "implementation detail" immediately comes to mind.
Beyond that, strings as constants enable extension as Eli implies. They also tend to be much more informative when debugging. "kCAGravityTop" is much more indicative than, say, "4".
In terms of performance, there is very little penalty to using strings. Static strings, of which the internal counterpart to every external declaration of just about every string constant is actually composed of, are handled efficiently by the compiler and the -isEqualToString: method's first test is pointer equality -- very fast. Not quite as fast as a switch(), but given the magnitude of code execution implied by the constant, the few cycles difference between switch() and string comparison is irrelevant.
I suspect that the reason is historical or stylistic more than anything else. This is how the NeXT frameworks did it and that created the Cocoa "style". As a benefit of this approach, inspecting the value in the debugger can give a meaningful value (e.g. @"CAGravityTop" or something like that instead of a meaningless int
). Because static strings are handled intelligently by the compiler, comparison can be by pointer comparison rather than string equality (see bbum's answer), so there's negligible performance hit for this approach.
One more reason I thought of in favour of NSString is that it can passed around wherever id
is accepted (such as userInfo
or as dictionary keys) while primitive types (enums) would need some kind of wrapper for this
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With