type name does not allow storage class to be specified - objective-c

#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.

Related

Equivalent of public static final variables

I understand that placing the word extern before a variable declaration in a header file declares the existence of a global static variable without initialising it. I also understand that if I import the file containing the extern variables, I can reference them without a class/file name. But where does one define them and their values?
What I am trying to do is create a class of constants with global constants that I want to use throughout an iOS application's code.
Does one put them inside the interface like this?
Example.h
#import <Foundation/Foundation.h>
#interface Constraints : NSObject
{
extern NSString * const PREFS_NAME;
}
Or does one put then outside of the interface like this
Example.h
#import <Foundation/Foundation.h>
extern NSString * const PREFS_NAME;
#interface Constraints : NSObject
{
}
Then in the implementation .m file how would one initialise the extern values?
Inside the implementation area like this?
Example.m
#import "Constraints.h"
#implementation Constraints
/**PRefecences name for the application**/
const NSString * PREFS_NAME = #"MyApp_Prefs";
#end
Or do initialise them outside of the implementation area like this:
Example.m
#import "Constraints.h"
/**PRefecences name for the application**/
const NSString * PREFS_NAME = #"MyApp_Prefs";
#implementation Constraints
#end
Or do I provide them their initial values in a constructor? or some arbitrary a static style method with + in front of it i.e. +(void) setAppConstraints;
I have tried several combinations, but always run into errors, such as "Redefinition of 'xVariable' with a different type". Or a something about "extern does not have an initialise interface" (or something like that, I forget). So I want to know how to declaire and initialise them properly to form the same role as public static final variables in Java.
Also what are the limits of the extern command? I know I can extern an NSInteger or NSString, but what about NSArray?
I am asking this question because there seems to be to much misleading, or incomplete, information regarding the use of extern in Objective-C. Many of the answers seem speculatory. My hope is for this question to be a good resource not only for me, but to limit further similar questions about the basics of extern.
You define it's value in the file inside which it's declared, which in your case is Example.m; You can still re-assign this variable, so the declaration in Example.h would look like this:
extern NSString * PREFS_NAME;
This way every file that imports Example.h has access to this variable. The equivalent of public static final in Objective-C is const. If you also want it to be public you should make it be a class instance variable, but in this case you don't need it because it's already accessible everywhere. So in this case it would be:
// .m file
NSString* const PREFS_NAME = #"MyApp_Prefs";
// .h file
extern NSString* const PREFS_NAME;
Also notice that const NSString* is different from NSString* const. The latter is a const pointer to NSString. The former hasn't sense even if it's a correct syntax. In Objective-C the const qualifier doesn't affect objects, instead there are mutable and immutable classes. It would have sense in C++ meaning that you can use just const methods on the instance.
extern is used to signal the compiler that you will be using a variable or a function that is defined in another compilation unit.
When you say extern const NSString *PREFS_NAME, you're saying "Replace all references in this compilation unit to PREFS_NAME to the variable PREFS_NAME as it is defined in another file." So when you try to assign PREFS_NAME in your .m, all you're doing is trying to assign a variable that, though it has a name, it doesn't exist. Declaring a variable extern is only a declaration of a variable or function, not a definition of that variable or function. It lets the compiler know that the name is in use, and that the linker will take care of what to do with it, but even if you provide a type here, it doesn't actually set aside space for the variable, it's expecting the space to be set aside in the compilation unit that's actually defining the variable.
You compile three or four different source code files together, three of them may declare:
extern int buffer[];
And one may declare
int buffer[BUFSIZE];
In its global scope, and the linker's job is to resolve the three declared references to extern buffer to the fourth's actual definition of the buffer.
extern is to C variables and functions much as #class is to Objective-C classes, it's a forward declaration, a promise to the compiler that you don't have to freak out when you see a name that's undefined here, because the linker will answer whatever lingering questions you may have.

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

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.