In Xcode / Objective C: Is there a syntax that you can force access to a global variable. I notice that a class variable silently hides any global variable. See example. Not suggesting it's a good idea but just curious.
int someVariable = 56;
#implementation Example {
int someVariable;
}
- (void)print {
printf("Var=%i\n", someVariable);
}
The convention used by Apple and most Objective-C developers is to capitalize global names, and if the project uses a prefix, to prefix them as well. So for example:
int SomeVariable = 56;
or
int XYZSomeVariable = 56;
That way your global names can never collide with names of instance variables (not class variables, by the way -- there is no such thing in Objective-C), local variables, or arguments so long as you observe the other half of the convention: local names always begin with a lowercase letter.
Edit
I should also mention that there's a longstanding convention in Objective-C to prefix instance variable names with an underscore, which would also help avoid the problem. In fact, the LLVM 4.0 auto synthesis feature now automatically synthesizes ivars with an underscore prefix for declared properties unless you tell it not to. So for example, if you had declared the instance variable in your example as follows:
#implementation Example
{
int _someVariable;
}
...the ivar couldn't have shadowed the global variable.
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.
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
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?)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?
It is not fully clear to me (other than for readability of the code), why you wanna create an internal variable with an underscore prefix when you create the property.
Since everything is handled internally, why bother to do so, since we do not add any code to the getter and setter?
And even if i gotta add some code to the getter or setter, i do not see why i cannot just do the check on myvar instead than having to check _myvar and then assign it to myvar.
Can anyone give me some explanation, other than "do it because that's what everyone does ?" I would like to understand the whole reason behind this practice (that seems to be pretty common even if there is no custom code for the getter and setter).
Thanks!
I've wondered this many times myself. Interested in other people's answer, but one reason I've found is that it forces you to notice if you're accessing the ivar directly when you should be using the getter/setter.
self.myvar = #"blah"; and _myvar = #"blah";
vs
self.myvar = #"blah"; and myvar = #"blah";
It's easy to leave the self. out by accident... it's a lot harder to put the _ in by accident.
An Objective-C property usually has a backing instance variable (I guess you know the difference between a property and an instance variable).
The property may have a different name than the instance variable.
For instance, you may have an instance variable named x, with a property named y.
You can synthesize the y property to the x variable using:
#synthesize y = x;
Now about the underscore.
It's a common practice to use an underscore prefix for instance variables, to prevent naming collisions, or compiler warnings (shadowed variable), when having for instance a method argument with the same name as an instance variable.
The underscore prefix also makes clear that you are referring to an instance variable.
By using the underscore prefix for instance variables, you're free to use the name without the underscore in method's arguments, stack variables, etc.
But when using a property, you usually don't want the user to write an underscore.
So you usually have an x property for an _x instance variable.
This is why you write:
#synthesize x = _x;
Let's take an example:
#interface Test: NSObject
{
int x;
}
#property( readonly ) int x;
#end
This is quite common... But now imagine this in the implementation:
- ( id )initWithX: ( int )x
{}
We have are a naming collision.
Inside our method, x will refer to the method's argument. And there is no pretty way to access the x instance variable.
Depending on your compiler's warning flags, this may also generate a warning (-Wshadow).
If you use an underscore prefix for your instance variable, everything is just simple:
- ( id )initWithX: ( int )x
{
if( ( self = [ super init ] ) )
{
_x = x;
}
return self;
}
No conflict, no naming collision, improved reading... Just a nice way...
When using a property of self, it's easy to forget the "self":
[self.field doSomething]; // what you probably want
[self setField:someObject]; // also kosher
self.field = someObject; // ditto, although not my style
vs.
[field doSomething] // might work.. but will bite you eventually
field = someObject; // almost certainly wrong anywhere outside a custom setter
If the property and the ivar are named identically, the latter cases will compile without complaint and appear to work... until they don't, and you get a weird hard-to-reproduce edge case bug.
If the ivar has a slightly different name, say with a trailing _ appended, the compiler will stop you and make you explicitly decide: do I want to refer to the property here, or the ivar directly?
(All that said, I am lazy and often do #synthesize field;, and replace it later with #synthesize field = field_; when I actually need the distinct ivar, say when it's custom-setter-writing time.)
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.