Where to declare an enum struct? - objective-c

This is just out of curiosity but when i declare an enum type, would it be better to have it within an implementation declaration or outside of it? What would be best practice? For example:
#implementation PostQuestionScene
enum popUpItems{
kExpiredBox,
kPauseBackground
};
vs..
enum popUpItems{
kExpiredBox,
};
#implementation PostQuestionScene ..

I tend to always have a typedef so it's just like another variable:
typedef enum {
kExpiredBox,
kPauseBackground
} popUpItems_t;
Then create instances of it.
popUpItems_t popUpItems;
If you will use it outside that module, put the typedef in the header so when the header is included, other modules have the typedef at their disposal (if they need to take it as an argument, for example,) otherwise put it in the implementation (think public/private variables.)

I don't think it makes any technical difference. I would place it before the #implementation (along with all other miscellaneous declarations) unless it is just used in one or a small group of methods, in which case I would place it immediately before those methods.
Of course, if it might be used by clients or subclasses it should be in your header file (where #interface is) so that the definition is visible to them.

Related

How to declare unknown enum in header?

I know you can use the #class word to declare an unknown class in an objective-c header file. Is there a way to declare an unknown enum inside a header class?
For instance, is there a way to prevent the compile error for someEnum?
#import <Foundation/Foundation.h>
#class UnknownClass;
#interface Foo
#property (nonatomic, strong) UnknownClass *someObject;
#property (nonatomic) UnknownEnum someEnum;
#end
Yes you can forward declare an enum:
enum things;
However I think you will run into issues if you start using compiler flags like -pedantic as I don't believe it's part of the ISO standard. I also think, like forward declaring a class, you can probably only use a pointer to it, as its size isn't known.
I've never, personally, ever had to do this and prefer to include the header file defining the enum (and I don't think forward declaring the enum is cleaner than including the file anyway).
Bottom line: Don't bother.
If you for some reason you do not want to add the #import or #include directive for the header that does declare the enum, then just type it as something else. All enum types are pretty limited to some form of int. Just declare it as similar. If you know you will get 0 or higher you could use NSUinteger. If you know you will get negative numbers, use NSInteger.
Either of those should be sufficient for your property declaration.
That is to say, named enums are nothing more than typdefs as far as using the value of an enum member or assigning that value to a variable.
Another option is to do #ifndef to define the self same type def.

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.

Where various variable and method types should be placed in a header

I've noticed that I get compilation errors if I place certain declarations in certain places in my header file. I've put comments into the code as to where I think certain things go; are they correct?
#interface Level : CCNode {
//Instance variables?
PlayBackgroundLayer* playBGLayer;
PlayUILayer* playUILayer;
PlayElementLayer* playElementLayer;
}
//Static methods?
+(void) InitLevel: (int) levelNumber;
+(Level*) GetCurrentLevel;
//Property declarations for instance variables?
#property (nonatomic, retain) PlayBackgroundLayer* playBGLayer;
#end
//Static variables?
Level* currentLevel;
PlayTilemapLayer* playTilemapLayer;
You are correct on all counts except one. Your last variables are not static variables, they are global variables. Static variables are simply variables that are declared with the static keyword and they mean something a little different than other languages. They aren't class variables, they are variables that are visible only to the file that they are declared in, and only then in the scope that it was declared (if you declare it inside a function other functions won't see it). However, as you would expect, they are only declared once regardless of how many instances you have. If you declare something outside an interface without the static keyword as you did, other classes will import them. However, this is not the ideal way to accomplish this (you might get redefinition errors if more than one class imports this header).
Also, one caveat, is that properties don't need to have an explicit backing variable (the compiler will create one for you if you use the #synthesize keyword), but of course if you desire one there is nothing wrong with it.
Finally, you should note that the only reason that your static methods class methods are not instance methods is because they start with a plus (+) character as opposed to a minus (-) character.
Instance variables usually don't need to be declared explicitly. They're created when you #synthesize the property. If you do want them, though, the (new) correct place* is at the top of the implementation block:
#implementation Level
{
PlayBackgroundLayer* playBGLayer;
PlayUILayer* playUILayer;
PlayElementLayer* playElementLayer;
}
Those aren't static methods, they're class methods, but, yes, that's where you declare them. Some people like to put #property declarations before the class methods, but that's a matter of opinion. Instance methods go after both of these, although technically speaking the order doesn't matter -- that is, the compiler doesn't care, it's just a matter of readability.
Those top-level variables need to go somewhere other than a header file, though. If you put them there you will get compilation errors because every file that imports the header will appear to be re-declaring storage for those variables, which isn't allowed.
Ususally you put such variables into a .m file. If you want them to only be visible from there, you would use static. If you want them visible from other files that import the header, you leave static off and declare the variable as extern in the header:
extern Level* currentLevel;
This lets the compiler know that the storage for the variable is reserved elsewhere.
*See "Class Interface" in TOCPL.

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.

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.