How do I declare a variable in the main.m file so that it is available in all the classes?
If I simply declare it in the main function, the compiler says it's undeclared in the class method.
Must I declare it in an object like this?
#public
type variable;
All you need is to use plain old C global variables.
First, define a variable in your main.m, before your main function:
#import <...>
// Your global variable definition.
type variable;
int main() {
...
Second, you need to let other source files know about it. You need to declare it in some .h file and import that file in all .m files you need your variable in:
// .h file
// Declaration of your variable.
extern type variable;
Note that you cannot assign a value to variable in declaration block, otherwise it becomes a definition of that variable, and you end with linker error complaining on multiple definitions of the same name.
To make things clear: each variable can be declared multiple times (Declaration says that this variable exists somewhere), but defined only once (definition actually creates memory for that variable).
But beware, global variables are a bad coding practice, because their value may be unexpectedly changed in any of files, so you may encounter hard to debug errors. You can avoid global variables using Singleton pattern, for example.
Not really sure why you want to do it, but you could if you wanted.
main.m:
int someGlobal = 0; ///< Added outside any function, at the top say.
SomeClass.m:
extern int someGlobal; ///< Added at the top, outside the class implementation.
...
- (void)useGlobal {
NSLog(#"someGlobal = %i", someGlobal);
someGlobal = 5;
NSLog(#"someGlobal = %i", someGlobal);
}
But please, think carefully before embarking on using something like this!
Besides debugging, I see no reason to even try and modify the main.m file to directly interact with your application logic.
You can try to define a constant on Your_project_name_Prefix.pch file, if that suits your needs. Or declare a static variable on your application delegate, or any of the classes of your app.
To learn more about constants and static variables, follow this link:
http://iosdevelopertips.com/objective-c/java-developers-guide-to-static-variables-in-objective-c.html
Related
#interface Foo : NSObject
{
extern int gGlobalVar;
int i;
}
-(void)setgGlobalVar:(int)val;
#end
#implementation Foo
-(void)setgGlobalVar:(int)val
{
i = 5;
NSLog(#"i = %i", i);
gGlobalVar = val;
}
#end
I can declare i in interface and use it in implementation without any errors. But I cannot declare a variable of the type extern in interface. Why is this so? Why do I get an error which says that: "Type name does not allow storage class to be specified"?
Short Description:
The bracketed section of a class's #interface OR #implementation is only for declaring instance variables (aka "ivar"). The extern keyword is only for use with global variable declarations (or functions, but that's another topic.)
Therefore, you cannot declare an extern ivar.
Gritty Details:
Variables are first declared, and then defined. This distinction is typically blurred for variables in local scopes, as a locally declared variable without an explicit definition will often be allocated and given a default value by the compiler.
Global variables are potentially available in any scope, provided that scope knows the global exists. That's where the keyword extern comes in -- it declares that the global variable exists, and was defined elsewhere. This is only useful when you want to access a global variable in different code files.
Best Practices: Your book has some code that declares an extern variable in an implementation file (e.g. ".m" files, etc.)... that can work, but it's a bad practice because you're making potentially bad assumptions about whether that global actually has a valid definition elsewhere. (But, fancy compilers will discover this type of error.)
Instead, the best practice is to declare an extern variable once in a header file, have an accompanying implementation file that's dedicated to defining the externs in that header, and then include that header in other implementation files that want to use that global variable.
int helloness;
#interface test : NSObject
#end
vs
#interface test : NSObject{
int helloness;
}
#end
Do I understand that following are true and the only meaningful differences between the above two blocks:
in both blocks, the implementation of test.m can use helloness variable internally, like an ivar
in the first block, helloness will exist for any class that imports this .h but is otherwise private only to test.m in the second block
In the first block, is this technically what is considered a "global variable" in that any class that imports this will have access to the same contents of helloness?
What happens if multiple header files have a declaration for helloness and you import them all?
Similar to this, consider this implementation:
#implementation AClass
int food=5;
Here, food acts like an internal iVar, even though it was not declared in any #interface ?
In your first example, helloness is a global variable. It can be seen by any file which imports that header. If you include multiple headers which also declare an int helloness variable, I believe you'll get a warning from the compiler, and all of them will point at the same memory location. If you include another header which declares a helloness of type other than int, I believe you'll get a compiler error.
In the second example, helloness is an instance variable (ivar). Its value (memory location) is specific to each instance of AClass. (Anything can access it: e.g. AClass *instance = [[AClass alloc] init]; instance->helloness = 7; However, direct access to ivars is generally avoided in ObjC -- we use accessors and/or properties instead.)
In the third case, food is still a global variable, but its visibility is restricted to the implementation file it's declared in. Any instance of AClass, as well as any other classes or categories or functions implemented in the same file, can reference food, and all those references are to the same memory location.
In your first example, helloness is a global variable. In your second example, it's an instance variable.
There can be only one global variable with a given name in your program. There is a copy of an instance variable for each instance of your class that's created during your program's execution. They're not semantically similar at all.
Having a global variable in a header file, as I presume you are doing in the first example since you refer to #importing it, is probably a bad idea. If it's not a tentative definition like yours is (for example if you instead had int helloness = 12;), you'll end up with multiply defined symbol errors at link time.
In your last example, food is still a global variable, but since it's likely to be in an implementation file (rather than a header), you probably won't run into any multiply defined symbol errors. It won't work like an instance variable, though - it's still a global variable.
By reading this post, It looks like certain rules should be considered when declaring global variables.
So I tried declaring global variables in the .m file. However, the code sense seems not happy to do this for me. For example, say I already have 2 lines in the .m file:
#implementation ViewController
#synthesize abc, xyz;
Now I want to add "BOOL isChecked;".
If I type this below "#synthesize" (or just between #implementation and #synthesize), the code sense actually suggests me to input "bool" (lower case) as I am typing "BOOL". If I type "BOOL" above "#implementation", it would suggest "BOOL" successfully.
Surely, the global variable is part of this class which means it should be inside the implementation. I am not sure why it doesn't like to let us do this.
This makes me feel that Objective-C doesn't like us to declare global variables below #synthesize. But my question is WHY? What I feel is that there may be a reason or Apple made a bug here.
Surely, the global variable is part of this class which means it should be inside the implementation. I am not sure why it doesn't like to let us do this.
Global variables aren't part of a class. Sure, you can put them inside an #implementation block, but they're really not a part of the class -- they're global -- so they don't really belong there.
Objective-C doesn't have class variables like Java or other languages do. You can fake them with global variables and class methods that access those variables, but at the end of the day, they're global, not specific to a class.
What the IDE's code sense help suggests is not an absolute indication of what the Objective C language "likes". Putting a global variable either outside or inside a class implementation generates equivalent compiled results from the Xcode Objective C compiler, and with no warnings.
However it might be considered better code style to put these declarations outside of the class implementation, as all global variables actually have global scope, not class scope.
In addition, you might want to assign an initial value to your global variables, instead of making any assumptions in your code of what that might be.
Objective-C does not have class variables. You declare a C global variable. This is how I do it:
Declare a static C variable. In your case:
static BOOL isChecked = NO;
Notice that I have initialized it. Notice that it is declared static, which restricts its visibility to the .m file it is declared in.
If you want a global object such as an array, you will need to initialize it:
static NSArray *myArray;
#implementation MyClass
+ (void)initialize {
if (self == [MyClass class]) {
myArray = [NSArray arrayWithObjects: ... ];
}
}
#end
Notice the if (self == [MyClass class]) check. +initialize will be called one or more times. Once when MyClass is used for the first time (e.g. call to +alloc). Possibly again when any subclass of MyClass is used for the first time. Hence the check to see if you are actually initializing MyClass, or a subclass of it.
And finally, if you want to access this variable outside of the code that it is declared in, create an accessor:
+ (BOOL)isChecked {
return isChecked;
}
Don't expose the global C variable by removing the static modifier. It makes it harder to debug, refactor or re-implement (what if isChecked suddenly depends on other state, how do you change this if it is directly used all over the place in other code?)
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 am working my way through some Objective-C code that I did not write and have found a variable declaration style that I am unfamiliar with. Can anyone tell me the scope of the variable 'myVar' in the class implementation below? Note that this appears in the '.m' file and not the interface declaration.
#implementation MyClass
#synthesize ivar1, ivar2;
NSString* myVar; // <- What is the intent?
- (id)init {
...
#end
To me the intention appears to be similar to that of a member variable. What are the advantages of declaring a variable in this way instead of using an ivar in the #interface declaration?
It's just a plain old global variable. There's only one instance of it, and it can be accessed by any code within the same file translation unit (the final file you get after running the preprocessor). Other translation units (that is, other .m files) can also access that global variable, but in order to do so, they need to use an extern statement:
extern NSString *myVar;
extern says "this is the name of a global variable, but it's defined in a different translation unit". The linker resolves all of the extern declarations at link time.
a poorly named global variable...
I'm not too experienced in ObjC but I'd say that is a global.