objective c - static variables puzzling behavior - objective-c

In an .h file I have the following line (outside of any #interface block):
static NSMutableDictionary *dictLookup;
In the corresponding .m file I try to initialize that static in the init method of the class:
dictLookup = [NSMutableDictionary dictionary];
dictLookup setValue:#"Hello?" forKey:#"Goodbye"];
However, when I insert breakpoints and do checks, dictLookup never becomes anything other than nil.
Also, I get a bizarre warning "Unused variable dictLookup" at compile time. Bizarre because if I delete the static declaration, then I get an "Undeclared identifier" compiler error at the lines in the init method.
I've since discovered there are better ways of doing what I want. But what was going on here? (1) Why can't I set dictLookup to anything?
Some sources seem to say that in C a static variable can only be used in the file in which it is declared. (2) If so, then why doesn't compiler fail with an error in the .m file? Given (1) that would seem to be the logical thing to design the compiler to do.
And (3) When I designed a new 'test' project from scratch, with a new .h/.m file combo like the one described, I WAS able to set dictLookup and insert keys. Why could accoutn for this difference?

When you put a declaration of a static variable in a .h file, it gets re-defined in every .m file from which the header is included. A brand-new variable will be created in each file, with the same name.
This is not an error in the .m file: the variable is local to that file, and invisible to the linker, so there are no "multiple definitions" error.
That's because your test project used a single .m file.
Some sources seem to say that in C a static variable can only be used in the file in which it is declared.
That is absolutely correct: a static variable is very much like a file-scoped global variable, it should be defined in the .m file. If you want to share a variable, it needs to be a global then. Declare it in the header with the extern keyword, like this
extern NSMutableDictionary *dictLookup;
and then define it in one of the .m files like this:
NSMutableDictionary *dictLookup;

Related

Declaring variable above vs below #interface

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.

objective-c - global variables

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

Newbie question -multiple parameters

I am trying to implement a private method which takes an NSMutableDictionary and a Player object as its parameters. As it is a private method, the only place that it exists is in the ".m" file.
It is declared as
-(void) incrementScore: (NSMutableDictionary*) scoreboard forPlayer: ( Player* ) player {
and I call it as follows :
[ self incrementScore:deuceScore forPlayer:p];
However,it won't compile - I get
may not response to message -incrementScore:forplayer
I'm not sure where my error lies - do I need to declare the method in the ".h" file, or elsewhere in the ".m" file, or have I just got the syntax completely wrong?
The compiler needs to find a declaration for your method somewhere before you use it. This be done in three way:
Declare the method in the (public) #interface for the class in its .h file .
Declare the method in a class extension (a semi-private #interface, usually at the top of the .m files).
Define the method somewhere in the #implementation before your first use of it.
This is only a warning not a compile error... (if you changed preferences to treat all warnings like error it'll be a compile error).
Probably the line calling the method is above (in the .m file) the declaration method. Move the method just below #implementation directive, or above the method with the calling line. The warning/error should disapper.

How to use global variables in Objective-C?

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.

What class of Objective-C variable is this?

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.