I have to assign a variable to a constant like this (the code below is at the beginning of my file code, before #implementation):
#ifdef DEBUG
NSString *hostStr=[[NSString alloc]init];
hostStr=#"xxx.mycompany.com";
static NSString * const host = hostStr;
#endif
If i do like so:
#ifdef DEBUG
static NSString * const host = #"xxx.mycompany.com";
#endif
That will work.
Actually, in my real case, host will contain the value of a global value (declared in the app delegate and initialized in another view controller). But for the sake of simplifying my problem, i use this example (since both cases give me the same error).
How can i fix this problem please. Thanx in advance.
There are a couple of issues here.
Constants that are set outside of any function cannot be "dynamic". This means that the compiler has to know what the constant value is before the program is run. If you say something like this:
static int x = myFunction(459);
The compiler can't know what myFunction() will return until the program is actually run.
This is why:
NSString *hostStr=[[NSString alloc]init];
causes a syntax error. The compiler will not execute any code when making a constant.
The solution is simple:
NSString *host=#"www.mycompany.com";
Notice that I didn't use the "static" qualifier. That would make "host" only available to the code in the file it was declared it. Dropping the "static" qualifier makes it global.
To access this global variable from another file, the other file needs to declare
extern NSString *host;
at which point the other file will be able to see the contents of "host".
Another thing to point out, is that this:
NSString *hostStr=[[NSString alloc]init];
hostStr=#"xxx.mycompany.com";
doesn't really do much. You create an NSString with alloc/init, then immediately assign
a constant to it, moving the NSString you created aside, without disposing of it, creating a memory leak. (If you have ARC enabled, then it's a non-issue. ARC knows all.)
Related
In the following class:
MGTileMenu
various extern NSString's are defined in the following way for use as notifications:
.h
extern NSString *MGTileMenuWillDisplayNotification; // menu will be shown
.m
NSString *MGTileMenuWillDisplayNotification;
It gets used as follows:
[[NSNotificationCenter defaultCenter] postNotificationName:MGTileMenuWillDisplayNotification
object:self
userInfo:nil];
My question is this: The extern NSString MGTileMenuWillDisplayNotification never gets initialized to any value - but this code works. I would have expected the implementation in the .m file to be:
NSString *MGTileMenuWillDisplayNotification = #"MGTileMenuWillDisplayNotification";
Why is this not necessary and what is going on here?
This means that the actual variable is defined in other parts of the program. Probably within some framework or library. You do not even have to have the related source.
The extern keyword tells the linker to look up the symbol table for a symbol named MGTileMenuWillDisplayNotification . (I think that would be a static variable, but not sure whether it coud be something else.)
NSString* tells the compiler to tread the memory where your pointer points to as NSString object. As usual. It is just that it is declared somewhere else and most probalby properly initialized somewhere else. It is in your scope of responsibility to ensure that it really is an NSString object which the documentation of the framework/library should tell you.
How should I declare a global variable in my Objective-C project?
Traditionally, global variables are declared in a header, and defined in a source file. Other source files only need to know how it is declared to use it (i.e. its type and its name). As long as the variable is defined somewhere in a source file, the linker will be able to find it and appropriately link all the references in other source files to the definition.
Somewhere in your header, you would declare a global variable like this:
extern int GlobalInt;
The extern part tells the compiler that this is just a declaration that an object of type int identified by GlobalInt exists. It may be defined later or it may not (it is not the compiler's responsibility to ensure it exists, that is the linker's job). It is similar to a function prototype in this regard.
In one of your source files, you define the GlobalInt integer:
int GlobalInt = 4;
Now, each file that includes the header will have access to GlobalInt, because the header says it exists, so the compiler is happy, and the linker will see it in one of your source files, so it too will be happy. Just don't define it twice!
However
You should consider whether or not this approach is useful. Global variables get messy for a number of reasons (trying to find out exactly where it is defined or declared, threading issues), there is usually not a need for global variables. You should perhaps consider using a singleton approach.
Don't. Global variables are often a sign of poor design. A common replacement in Objective-C is a class method that returns an object (that may or may not be a singleton), such as [NSUserDefaults standardUserDefaults] or [UIDevice currentDevice].
However, if you must use a global variable, read on.
In your header:
extern NSString *someString;
extern NSInteger someInteger;
In your implementation file:
NSString *someString = #"DEFAULT_VALUE";
NSInteger someInteger = DEFAULT_VALUE;
In my experience there are few instances when a program doesn't need, at least, some sort of data or utility/helper methods that can be accessed throughout the program.
They way I deal with this, rather than using global variables is to create what I call a 'project applicance', which is essentially just a class with a bunch of static methods.
It could be implemented multiple ways, but I use a singleton and just have the static methods call through to the single instance of the appliance class. For example, in my project Oovium I have:
Oovium.h:
#interface Oovium : NSObject {
UIWindow* _window;
}
+ (UIWindow*) window;
Oovium.m:
#implementation Oovium
static Oovium* oovium;
- (UIWindow*) window {return _window;}
+ (void) initialize {
oovium = [[Oovium alloc] init];
}
+ (UIWindow*) window {return [oovium window];}
I then include Oovium.h in my Oovium_Prefix.pch file so that it is automatically included in all of my files.
Globals rock! I don't know what everyone is scared of. I used them successfully here.
Passing Data between View Controllers
Also used UIStepper to adjust values in another viewController.
I could see them being an issue is larger programs, and in my opinion the singleton thing is just a masked global. Keep it simple, if your app is simple that is.
I frequently see a code snippet like this in class instance methods:
static NSString *myString = #"This is a string.";
I can't seem to figure out why this works. Is this simply the objc equivalent of a #define that's limited to the method's scope? I (think) I understand the static nature of the variable, but more specifically about NSStrings, why isn't it being alloc'd, init'd?
Thanks~
I think the question has two unrelated parts.
One is why isn't it being alloc'ed and init'ed. The answer is that when you write a Objective-C string literal of the #"foo" form, the Objective-C compiler will create an NSString instance for you.
The other question is what the static modifier does. It does the same that it does in a C function, ensuring that the myString variable is the same each time the method is used (even between different object instances).
A #define macro is something quite different: It's "programmatic cut and paste" of source code, executed before the code arrives at the compiler.
Just stumbled upon the very same static NSString declaration. I wondered how exactly this static magic works, so I read up a bit. I'm only gonna address the static part of your question.
According to K&R every variable in C has two basic attributes: type (e.g. float) and storage class (auto, register, static, extern, typedef).
The static storage class has two different effects depending on whether it's used:
inside of a block of code (e.g. inside of a function),
outside of all blocks (at the same level as a function).
A variable inside a block that doesn't have it's storage class declared is by default considered to be auto (i.e. it's local). It will get deleted as soon as the block exits. When you declare an automatic variable to be static it will keep it's value upon exit. That value will still be there when the block of code gets invoked again.
Global variables (declared at the same level as a function) are always static. Explicitly declaring a global variable (or a function) to be static limits its scope to just the single source code file. It won't be accessible from and it won't conflict with other source files. This is called internal linkage.
If you'd like to find out more then read up on internal and external linkage in C.
You don't see a call to alloc/init because the #"..." construct creates a constant string in memory (via the compiler).
In this context, static means that the variable cannot be accessed out of the file in which it is defined.
For the part of NSString alloc, init:
I think first, it can be thought as a convenience, but it is not equally the same for [[NSString alloc] init].
I found a useful link here. You can take a look at that
NSString and shortcuts
For the part of static and #define:
static instance in the class means you can access using any instance of the class. You can change the value of static. For the function, it means variable's value is preserved between function calls
#define is you put a macro constant to avoid magic number and string and define function macros. #define MAX_NUMBER 100. then you can use int a[MAX_MUMBER]. When the code is compiled, it will be copied and pasted to int a[100]
It's a special case init case for NSString which simply points the NSString pointer to an instance allocated and inited at startup (or maybe lazily, I'm not sure.) There is one one of these NSString instances created in this fashion for each unique #"" you use in your program.
Also I think this is true even if you don't use the static keyword. Furthermore I think all other NSStrings initialized with this string will point to the same instance (not a problem because they are immutable.)
It's not the same as a #define, because you actually have an NSString variable by creating the string with the = #"whatever" initialization. It seems more equivalent to c's const char* somestr = "blah blah blah".
I am a little confused as to when it's best to use:
static NSString *AppQuitGracefullyKey = #"AppQuitGracefully";
instead of
#define AppQuitGracefullyKey #"AppQuitGracefully"
I've seen questions like this for C or C++, and I think what's different here is that this is specifically for Objective C, utilizing an object, and on a device like the iPhone, there may be stack, code space or memory issues that I don't yet grasp.
One usage would be:
appQuitGracefully = [[NSUserDefaults standardUserDefaults] integerForKey: AppQuitGracefullyKey];
Or it is just a matter of style?
Thanks.
If you use a static, the compiler will embed exactly one copy of the string in your binary and just pass pointers to that string around, resulting in more compact binaries. If you use a #define, there will be a separate copy of the string stored in the source on each use. Constant string coalescing will handle many of the dups but you're making the linker work harder for no reason.
See "static const" vs "#define" vs "enum". The main advantage of static is type safety.
Other than that, the #define approach introduces a flexibility of inline string concatenation which cannot be done with static variables, e.g.
#define ROOT_PATH #"/System/Library/Frameworks"
[[NSBundle bundleWithPath:ROOT_PATH#"/UIKit.framework"] load];
but this is probably not a good style :).
I actually would recommend neither, you should use extern instead. Objective-c already defines FOUNDATION_EXPORT which is more portable than extern, so a global NSString instance would look something like this:
.h
FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey;
.m
NSString * const AppQuitGracefullyKey = #"AppQuitGracefully";
I usually put these in declaration files (such as MyProjectDecl.h) and import whenever I need.
There are a few differences to these approaches:
#define has several downsides, such as not being type safe. It is true that there are workarounds for that (such as #define ((int)1)) but what's the point? And besides, there are debugging disadvantages to that approach. Compilers prefer constants. See this discussion.
static globals are visible in the file they are declared.
extern makes the variable visible to all files. That contrasts with static.
Static and extern differ in visibility. It's also notable that neither of these approaches duplicates the string (not even #define) as the compiler uses String Interning to prevent that. In this NSHipster post they show proof:
NSString *a = #"Hello";
NSString *b = #"Hello";
BOOL wtf = (a == b); // YES
The operator == returns YES only if the two variables point at the same instance. And as you can see, it does.
The conclusion is: use FOUNDATION_EXPORT for global constants. It's debug friendly and will be visible allover your project.
After doing some search (this question/answer among other things) I think it is important to say that anytime when you are using string literal #"AppQuitGracefully" constant string is created, and no matter how many times you use it it will point to the same object.
So I think (and I apologize me if I'm wrong) that this sentence in above answer is wrong: If you use a #define, there will be a separate copy of the string stored in the source on each use.
I use static when I need to export NSString symbols from a library or a framework. I use #define when I need a string in many places that I can change easily. Anyway, the compiler and the linker will take care of optimizations.
USING #define :
you can't debug the value of identifier
work with #define and other macros is a job of Pre-Processor,
When you hit Build/Run first it will preprocess the source code, it will work with all the macros(starting with symbol #),
Suppose, you have created,
#define LanguageTypeEnglish #"en"
and used this at 2 places in your code.
NSString *language = LanguageTypeEnglish;
NSString *languageCode = LanguageTypeEnglish;
it will replace "LanguageTypeEnglish" with #"en", at all places.
So 2 copies of #"en" will be generated.
i.e
NSString *language = #"en";
NSString *languageCode = #"en";
Remember, till this process, compiler is not in picture.
After preprocessing all the macros, complier comes in picture, and it will get input code like this,
NSString *language = #"en";
NSString *languageCode = #"en";
and compile it.
USING static :
it respects scope and is type-safe.
you can debug the value of identifier
During compilation process if compiler found,
static NSString *LanguageTypeRussian = #"ru";
then it will check if the variable with the same name stored previously,
if yes, it will only pass the pointer of that variable,
if no, it will create that variable and pass it's pointer, next time onwards it will only pass the pointer of the same.
So using static, only one copy of variable is generated within the scope.
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";
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.
The best argument I have heard is that const strings show up in the debugger, whereas macros do not.
static NSString * const SERVER_URL = #"http://subdomain.domain.edu.ar/Folder/";
As far as I know, #define only lets you define C-style string constants. To create a constant NSString object, you have to declare it in the header, and then give it a value in one of your .m files.
Header file:
extern NSString *MyConstantString;
Main file:
NSString *MyConstantString = #"String value";