In my iOS/Objective C projects, I often have a constants.h file with my API keys and such. Until today, I've been declaring my constants as static const like so:
static NSString * const kAPIKey = #"wembvkejrvb43789gvbiu2bvfake";
This works fine, but with the unfortunate downside that I can only create constants for primitives and NSString literals, essentially. Other objects, such as UIColor objects, cannot be stored in this constant as they cannot be initialized with a static literal syntax (my understanding, citation required).
After reading some C++ docs, I understand a few things:
The static is unnecessary, as const are implicitly static.
Calling NSString * const x is actually declaring a constant and immutable value in x. I cannot change the value, but may be able to change what x points to.
This const has internal linkage, meaning the the value is defined right away (presumable at compile time).
Are these conclusions correct?
How does an extern const differ? I assume they are externally linked (thus the extern keyword). Are they defined at run time? Can I create some sort of dynamic extern const that can be set with a value returned by a class method?
For example, I would like to create a globally-scoped constant that contains a UIColor value. I would like to construct this color value using the [UIColor colorWithRed:green:blue:alpha:] class method. This clearly doesn't work with the internally linked constants I've been using (I'm assuming because it happens at compile-time) - but is it possible using an external constant, possibly set up in the +initialize method?
Any elaboration on the details of this behavior would be immensely helpful.
The static is unnecessary, as const are implicitly static.
No, that's not true.
static when used at file scope (i.e. outside any method or function) means that the variable is visible only within that file.
extern means that the variable is defined in some other file.
const means that the variable cannot be modified.
Consider strings. Often, you'll have an implementation file (name ends in .m) that defines some constant string pointer:
NSString *const SomeString = #"some string";
You might want to use that same constant from other files. If so, you could add a declaration to the header (name ends in .h) file that explains to the compiler that the variable is defined elsewhere:
extern NSString *const SomeString;
and that would let you use SomeString in any file that imports the header file. On the other hand, you might decide that you definitely do not want the constant used outside the implementation file. In that case, you could declare it static (in the implementation file again):
static NSString *const SomeString = #"some string";
and that would prevent its use from outside the file.
Calling NSString * const x is actually declaring a constant and immutable value in x. I cannot change the value, but may be able to change what x points to.
Right, it declares the pointer x to be constant -- you can't change it. You also can't change the value that it points to if it's actually a NSString because an instance NSString isn't mutable.
This const has internal linkage, meaning the the value is defined right away (presumable at compile time).
I'll take the 5th on that -- I'm not sure exactly how the compiler deals with constant strings. I think it's safe to use that as a mental model, though; the string will in any case be defined before your code ever gets to use it.
On your specific programming question, how to create a compile-time defined color object: you can't, because, apart from the handful for which the language supplies literal syntax, objects are created at runtime.
But you can still do it elegantly at runtime, without any addition to global scope, the same way the sdk does...
#interface UIColor (RainbowAddition)
+ (UIColor *)chartruseColor;
#end
#implementation UIColor (RainbowAddition)
+ (UIColor *)chartruseColor {
// bonus: this is really chartruse... according to the internet
return [self colorWithRed:0.5 green:1.0 blue:0.0 alpha:1.0];
}
#end
http://cloford.com/resources/colours/500col.htm
Objective-C is a pure extension of C, C++ is not.
At global scope:
in C (and Objective-C) writing const is equivalent to extern const (external linkage);
in C++ writing const is equivalent to static const (internal linkage).
Both in C (and Objective-C) and C++, to create a global-scoped const you can define it, just one time, in one source file like extern const TYPE identifier = VALUE; and declare it (typically in an header file) like: extern const TYPE identifier; (read it: I defined this const elsewhere at global linkage level).
Related
My project contains more that 5000 constants over the classes, I want to reduce the memory for those constants. So my doubt is which is the best way to use to define the constants in Objective-C.
#define
or
const
I think the best method to solve your task is using #define directive. Define directive doesn't use memory in the runtime. This directive is executed by a compiler.
Example:
#define MY_CONSTANT #"Hi"
Using in code:
NSString* string = [MY_CONSTANT stringByAppendingString:#" Mac"];
Here you can read about memory allocation for const variables.
Just expanding one of my comments above. The question is
#define MYSTRING #"This is a string"
versus say
NSString *const myString = #"This is a string";
The actual outcome is tool specific. However, examining a binary generated from Xcode, one will find the following:
As expected, both strings must be encoded in the binary, in this case, they will be the __TEXT __cstring as can be verified by running otool -v -s __TEXT __cstring BINARYNAME
Contents of (__TEXT,__cstring) section
0000000100002f19 This is a string
Keep in mind that this technically consumes memory, as the __TEXT is very much loaded into memory during runtime. The larger question, which is related to what the OP was asking is along the lines of "what additional memory outside of __TEXT is incurred by using const".
Remember that the linker will optimize multiple instances of a string. In other words:
NSString *const string1 = #"I'm a string";
NSString *const string2 = #"I'm a string";
will only result in one instance of that string in __cstring in the final binary.
So the overhead of using NSString * seems to be at least a pointer reference. This will be placed either in the __DATA __data or __DATA __const section depending on how it is defined:
NSString *const myString = #"This is a string";
Which would yield:
0000000100003068 (__DATA,__const) non-external (was a private external) _myString
NSString *myString = #"This is a string";
Which would yield:
0000000100003d60 (__DATA,__data) non-external (was a private external) _myString
Note that NSString *const is the way you should be defining it.
So assuming a 64-bit target, your 5,000 string overhead as a const would at least be 40,000 bytes or ~39K. I say at least in case there is some other hidden thing that is being done. But in general, I would expect the pointer to just point to the string in memory.
For most apps, this is probably not very large in the scope of things. So the question one should be asking is what advantages are there for using const?
And for that aspect, I'll save typing and refer you to the following links. It is preferred to use const as the compiler can type check.
Objective-C : #define vs extern const
#define vs const in Objective-C
It actually depends upon case to case. For your case i think #define seems to be a better option.
As far as I know:
For #define --> No memory access. As token_string will be substituted for each occurrence of identifier, exe size increases(storage of literal).
For const --> memory will be hit for every access of variable, extra exe size increases(storage of variable and storage of literal which is pointed or referred by variable).
For better understanding, please visit following links
"static const" vs "#define" vs "enum"
and static const vs #define
I was watching the F8-2016 Building iOS Tooling at Facebook Scale video, when I've noticed an interesting code part at 7:01.
Facebook defined a static constant in Objective-C this way:
static __unsafe_unretained NSString * const kAuthorKey = #"AUTHOR";
Up to now, I declared my static constants the same way, but without the __unsafe_unretained. Without this modifier, the constant will be strong, but since it exists always during the application run, it doesn't matter if it is strong or __unsafe_unretained.
Am I missing something? Do Facebook has any reason to use __unsafe_unretained?
I've find it frustrating to define constants in the .h as externals and then assign the constants in the .m file. Seems so redundant. Is there any reason not to just define the constants in the header file?
Typical implementation would be:
// Constants.h
#interface Constants : NSObject
extern NSString *const kPCFavorites;
#end
The implementation would then be:
// Constants.m
#implementation Constants
NSString *const kPCFavorites = #"PCFavorites";
#end
However, I can just do this:
// Constants.h
static NSString *const kPCFavorites = #"PCFavorites";
#interface Constants : NSObject
#end
Obviously, this last definition doesn't even need an interface or implementation so both could be left out and become:
// Constants.h
static NSString *const kPCFavorites = #"PCFavorites";
with no .m file at all.
This seems much cleaner to me. Why wouldn't we implement constants this way? I've defined them both ways and I get no compile or runtime errors in XCode 5.
Because
static NSString * const kPCFavorites = #"PCFavorites";
declares a variable, not a constant. C doesn’t actually have a way to declare a symbolic constant (besides enum, which only works for integers).
As a result, if you use this method, every file that #includes your header will have its own variable called kPCFavorites. Historically, that would have meant that your program would increase in size because of all of the copies of kPCFavourites and the string #"PCFavourites", although more modern linkers may manage to get rid of some or all of the duplication (certainly I’d expect the linker to leave you with only one copy of the string itself; whether or not it can currently get rid of the extra pointer variables I’m not sure — but it’s easy to test).
static variables have file scope. If you compile a file which includes a header file with a static variable, that variable will exist in the compiled file. If you compile another file with the same header file, you have a second static variable and so on. If you include the header from 1000 source files, you get 1000 static variables, all with the same name.
I have a method , which takes the following argument.
void callAMethood(const void *iVar){}
now here i am not clear on how should i pointer
the following seems to be quite simple,where i just pass the address instead of value.
NSString *a=#"Hi";
callAMethood(&a);
But, the following seems to work well, but understanding the syntax is difficult.
char const * const a="HI";
callAMethood(&a);
or even this works callAMethood(a);
As xlc points out, both are wrong.
NSString *a=#"Hi";
callAMethood(&a); // This passes a NSString **
char const * const a="HI";
callAMethood(&a); // This passes a char const * const *
Both work, because a pointer to a pointer can stil be cast to a void *.
It is incredibly unlikely that you intended either, though.
Take advantage of C being type-checked at compile time and be more specific with your types.
void awesome_function(NSString *amazingString);
NSString *yay = #"oh my god yes";
awesome_function(yay); // ok
awesome_function(&yay); // compiler error
In short: unless you have a very good reason for using a void * (which I would consider unlikely for a Cocoa(Touch) app), don't.
If you don't want compile-time type checking, use something like Python. If you want to be able to handle different Objective C object types, that's what id is for.
You ask what you should pass to the function (it is not the declaration of a method):
void callAMethood(const void *iVar) {...}
The answer is nobody can tell you!
Your function takes a value of type void * - this type is typically used in C to mean a "pointer to anything". It is not a type that would be used for a function that took a pointer to any object, that would be id.
But that doesn't get us very far, as we've no idea what callAMethood is expecting we've no idea what to pass it - we cannot tell you the answer.
Now you give the example:
NSString *a = #"Hi";
callAMethood(&a);
That is a valid call, it passes a pointer to the variable a. However:
callAMethood(a);
is also a valid call, it passes the pointer which is stored in the variable a. Without any knowledge of what callAMethood is expecting we cannot tell you which is the correct call. The same applies to your second example.
HTH
Every pointer can be converted to void * implicitly.
EDIT:
As Kevin said, only data pointer.
As CRD said,
The answer is nobody can tell you!
without the information of the function of callAMethood. All of those invoking are valid grammatically(can be compiled), howerver, invalid semantically usually unless callAMethood really doesn't care about which type iVar(e.g. it just prints the pointer).
What people said above is correct but you can also use UTF8String to get a const char * from a NSString
const char * myStr = [a UTF8string];
callMehtod(myStr);
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html
I have a library of my own. And there are lots of constants defined in headers (for example animation duration). But, all my headers are visible and changeable. How can I prevent others to change my default values?
There are some const value in headers of Apple libraries like this:
CA_EXTERN NSString * const kCATransitionMoveIn
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
Objective-C is still, well, C. Maybe older systems had issues, which is why you see the macros there. Anyway, you should still be safe with any built-in type.
If you declare something as "extern" the compiler will treat it something like, "OK, I see that someone has declared and external thingy. I don't have to know what it is, because some external unit will define it. The linker will handle the rest.
That paragraph will get me in trouble with the C-police, but it's close enough for a practical explanation. Thus, you can do this in your header file...
extern int const TheAnswerToLifeTheUniverseAndEverything;
And then, in one of your implementation files (outside of the #implementation/#end section)...
int const TheAnswerToLifeTheUniverseAndEverything = 42;
Note, in "modern" Xcode versions, you can do the same thing with objects. Note the "const" which means we have a constant-pointer-to-NSString.
// In header
extern NSString * const TheAnswerToLifeTheUniverseAndEverythingString;
// In source
NSString * const TheAnswerToLifeTheUniverseAndEverythingString = #"42";