I've reading in several post and in Apple's code guidelines that in Objective-C String constants should be defined as extern NSString *const MY_CONSTANT;
and that the #define directive should be avoided. Why is that? I know that #define
is run at precompile time but all string will share the same memory address. The only advantage I read was that if the constant must be updated or changed you don't have to recompile your entire project. So that i s the reason why #define should be avoided?
Thanks
UPDATE: In this case is good to use a #define or there is a better approach?
/* Constants Definition */
#define SERVER_URL @"http://subdomain.domain.edu.ar/Folder/"
NSString *const ServerURL = SERVER_URL;
NSString *const LoginURL = SERVER_URL@"welcome.asp";
NSString *const CommandURL = SERVER_URL@"com.asp";
Objective-C is the primary programming language you use when writing software for OS X and iOS. It's a superset of the C programming language and provides object-oriented capabilities and a dynamic runtime.
In my opinion, probably the biggest difference is the syntax. You can achieve essentially the same things in either language, but in my opinion the C++ syntax is simpler while some of Objective-C's features make certain tasks (such as GUI design) easier thanks to dynamic dispatch.
While Objective-C is still supported by Apple and will likely not be deprecated anytime soon, there will be no updates to the language.
Objective-C has a superior runtime compared to Swift. It's probably going to be several years before Swift can catch up. If you're using powerful SDKs, Objective-C is also your best option here as well. I'd still recommend that new developers start off learning Swift.
A practical reason to use the constant as opposed to the definition is that you can do direct comparisons (using ==) instead of using isEqual:
. Consider:
NSString * const kSomeStringConstant = @"LongStringConstantIsLong";
...
[someArray addObject:kSomeStringConstant];
if ([someArray lastObject] == kSomeStringConstant)
{
...
}
This would work, since the ==
comparison would be comparing identical const pointers to a single NSString
object. Using #define
, however:
#define STRING_CONSTANT @"MacrosCanBeEvil";
...
[SomeArray addObject:STRING_CONSTANT]; // a new const `NSString` is created
if ([someArray lastObject] == STRING_CONSTANT) // and another one, here.
{
...
}
This would not work out, since the two strings would have unique pointers. To compare them effectively, you would have to do a character-by-character comparison using isEqual:
if ([[someArray lastObject] isEqual:STRING_CONSTANT])
{
...
}
This can be far more costly in terms of execution time than the simple ==
comparison.
Another motivation could be the size of the executable itself. The #defined constant would actually appear, in place, wherever it was used in the code. This could mean that the string appears many times in your executable. In contrast, the constant should (with modern compilers) be defined only once, and all further usages would make reference to the pointer to that one definition.
Now, before anyone yells at me for premature optimization, consider that the two approaches are almost identical in terms of implementation, but the const pointer method is far superior in terms of code size and execution time.
It's not necessarily guaranteed that there will only be one NXConstantString object for a given string literal in an entire application. It seems pretty likely that different compilation units might have different objects for the same constant string. For example, if somebody writes a plugin, one constant string will be generated for occurrences of that NSString literal in the plugin and one will be generated for occurrences in the host application, and these will not be pointer-equal.
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