Where should I define my enumerations? - objective-c

I have this enumeration:
enum battleType {localEnemy,multiplayerEnemy};
Which is declared in the .h file of my game battle scene. However, I would like to also use those two keywords in my party screen (which is another .h file). Do I have to declare this same enumaration twice (in both .h files), or is there a way to just declare it once and use it everywhere in my project?
As a side note, those keywords are exactly the same as integers, right? So I can't really store them as objects in my array, and instead I have to create a NSNumber instance for this, right?

Declare it in the header file it belongs into. In your case that would probably be BattleScene.h or something like that.
In the other file where you also have to use it you #import BattleScene.h.
If you use typedef, you don't have to write enum all the time. Also, it a good practice to use a uniform prefix in your enums. This makes your code more readable and autocomplete can help you when using the enum.
typedef enum {BattleTypeLocalEnemy, BattleTypeMultiplayerEnemy} BattleType;

There is a way. Create a new .h file (New File -> C and C++ -> Header) and put in your enum. Then just #import it into the battle scene header and the party scene header.
Your other question: Yes, they are really ints, shorts, or some other C integer type.

Related

XCode Header Search Paths for global struct

I created a struct called PointInt that is simply two integers (like CGPoint but with ints) and I want it to be a global struct just like CGPoint. I also created a category for NSValue for this.
I've looked all over the Internet and it seems that Build Settings -> Header Search Paths is the way to go. However, I have no idea what values to put into it. I've tried $(PROJECT_DIR)/PointInt/** and a bunch of similar strings but the compiler does not recognize it. How do I #import a .h file for the struct, then another .h and a .m for the category? And is there anything else that has to be done?
Add the header file with the struct to your prefix header. One will have been automatically created for you when you created the project called [project]-Prefix.pch in the "Supporting Files" directory.
Add it in between #ifdef __OBJC__ and #endif.
It will then be available throughout your project.

Where would I place a global utility function in Objective C?

When writing an iOS app, where would I place a function that I intend to use from any other file?
For example, a function to convert a NSDate to a relative time string ("5 secs ago").
Would I make a class and make these functions all static?
Functions can be placed wherever convenient. If a function or group of functions is likely to be imported in many places, you can declare and implement them in their own .h/.m pair. So for example you might implement your date conversion function in a file named XYZDateUtilities.m, and declare it in XYZDateUtilities.h.
Declaring functions with the static qualifier would limit their scope to the file in which they were declared, so you wouldn't want to do that; in fact you'd want to do the opposite -- declare them as extern in the .h file so that they'll be visible in other files.
You have a couple options:
1) If you're extending the behavior of a class (such as the NSDate string conversion method you described), it may work best to simply create a category on said class.
Here's a tutorial on iOS categories:
http://mobile.tutsplus.com/tutorials/iphone/objective-c-categories/
Important Note:
Categories change a class's behavior (if you override a method) everywhere within the project whether or not you include the header (.h) file in another specific class's imports
For this reason, it's generally best to not override methods via a category, but instead, to create a subclass if you want to change certain methods.
For adding new methods, however, categories can be very convenient and useful.
2) If you want to create a new class that's imported everywhere, you can create said class and put its header import, i.e. #import "MyClass.h", into your project's prefix.pch file (found under the "supporting files" group within the project by default).
Anything that you put into the prefix.pch file will be available anywhere within your app. This is also a useful place to put constants (such as strings) or define enums that are used across many classes within the app.
I hope this helps. Let me know if further clarification is needed, and I'll do my best to help.
Cheers!
Another option would be to create a class for your helper methods and implement all the helpers as class methods.
e.g. HelperClass.h
+ (NSString *)getFrenchCapital
e.g. HelperClass.m
+ (NSString *)getFrenchCapital
{
return #"Paris";
}
Then import your helper class wherever you need it, and simply call the class methods:
e.g. Foo.m
#import "HelperClass.h"
...
- (void)logFrenchCapital
{
NSLog(#"Capital of France: %#", [HelperClass getFrenchCapital]);
}
If you make all functions static in a class, then alternative is to just define functions in .m file, and extern functions in .h file, just like what you do in C.

options to forward declare a C typedef in obj-c #interface

My obj-c class uses a C library (the Chipmunk physics engine), which has an Obj-C wrapper interface.
I want to add a property with a chipmunk type (cpLayers) to my object, like so:
#interface
#property cpLayers layers;
...
The easiest way is to #import "ObjectiveChipmunk.h", but that seems ridiculous to import all of the headers just to get one measly type.
If I #import the C "chipmunk_types.h" file where cpLayers is defined "typedef unsigned int cpLayers;", I get compiler errors related to ARC. They are bridge/casting errors in a macro that is defined in chipmunk_types.h and used in my .m file.
If I add just the definition, or #include chipmunk_types.h, I get redefinition errors.
Is there any better way to do this? And WHY the ARC errors?
Take a look at the ObjectiveChipmunk.h, that is where it overrides the basic Chipmunk types using preprocessor defines. You can add those defines as compiler flags if you want to work around the problem, but I wouldn't really worry about it. You are already doing Objective-C programming after all, have you ever looked at the gargantuan amount of includes that get pulled in when you import something as innocuous as Foundation.h? Importing the full ObjectiveChipmunk.h header is like 1% in comparison.

How can I get a method to return a Random object of type NSObject

I as a learning exercise of Objective C I need to write a method that returns a Random NSObject.The approach that I tried to follow was to trying to get a list of all runtime objects and the itirate through and get an NSObject and return that.
Firstly I am not sure if that is the best approach. Secondly the code I am using is based on this and objc_getClassList link but in Xcode4 I am getting compile time error
warning: Semantic Issue: Implicit declaration of function 'objc_getClassList' is invalid in C99
warning: Semantic Issue: Implicit declaration of function 'classIsSubclassOfClass' is invalid in C99
I have tried adding following headers but no good
#import <objc/runtime.h>
#import <objc/objc-class.h>
#import <objc/objc-runtime.h>
but neither helped me and still have the warning.
So can I please some help with these two things 1- Is this the right approach and what is if not to achieve what I am trying to achieve 2- How can I get this code to not give warnings in Xcode 4.
Well, objc_getClassList is declared in objc/runtime.h, so including or importing that should do it.
For the other part, you simply need to declare your function before you use it. At the top level of the file, or in a file that you then include, you put the function header, without the body:
BOOL classIsSubclassOfClass( const Class aClass, const Class subclass );
This lets the compiler know about the function; you can then #include this declaration in any file that needs to use the function, while defining it (i.e., filling out the body) wherever you like.
So what you want is to get a class, any class, that inherits from NSObject?
I do not think this is the right approach at all. I can not see the need to get any random class. What would you do with it?
Maybe what you want to is add a subset of known classes that are of use to use in an array. And then pick one at random from that array.

Forward-declare enum in Objective-C

I'm having trouble with enum visibility in an Objective-C program. I have two header files, and one defines a typedef enum. Another file needs to use the typedef'd type.
In straight C, I would simply #include the other header file, but in Objective-C, it's recommended not to use #import between header files, instead using forward #class declarations as needed. However, I can't figure out how to forward-declare an enumeration type.
I don't need the actual enumerated values, except in the corresponding .m implementation file, where I can safely #import away. So how can I get the typedef enum to be recognized in the header?
Most recent way (Swift 3; May 2017) to forward declare the enum (NS_ENUM/NS_OPTION) in objective-c is to use the following:
// Forward declaration for XYZCharacterType in other header say XYZCharacter.h
typedef NS_ENUM(NSUInteger, XYZCharacterType);
// Enum declaration header: "XYZEnumType.h"
#ifndef XYZCharacterType_h
#define XYZCharacterType_h
typedef NS_ENUM(NSUInteger, XYZEnumType) {
XYZCharacterTypeNotSet,
XYZCharacterTypeAgent,
XYZCharacterTypeKiller,
};
#endif /* XYZCharacterType_h */`
The answer to your question is to either go ahead and import the typedef header file or to use a generic type like NSInteger instead of the enum type.
However, there is more reason to not importing a header file than just compile speed.
Not importing a header file also reduces your inadvertent access to extraneous classes.
For example, say you have a TrackFileChanges class that tracks the file system for changes to a specific file, and you have a CachedFile class that stores cached data from a file. The latter might use a private ivar of type TrackFileChanges*, but for uses of CachedFile, this is simply an implementation detail (ideally, the ivar would be auto-generated with a private property using the new runtime, but thats not possible if you're using the old run time).
So clients that #import "CachedFile.h" probably do not need or want access to TrackFileChanges.h. And if they do, they should make it clear by #importing it themselves. By using #class TrackFileChanges instea of #import "TrackFileChanges.h" in CachedFile.h you improve the encapsulation.
But all that said, there is nothing awrong with importing a header file from a second header file if the second header wants to expose the first to all clients. For example, header files that declare classes need to be imported directly in subclassing header files, and header files declaring protocols might well be imported directly (although youy can use #protocol ABC; to avoid this).
Go ahead and use #import. The only reason people recommend to use #class when possible is because it makes your code slightly faster to compile. However, there is no issue with #importing one .h file from another. In fact, you need to do this when extending another class.
If you are ok using compiler extensions, you could use this order in Clang:
enum Enum;
typedef enum Enum Enum2;
void f(Enum2); // ok. it sees this type's true name.
enum Enum {
E_1
};
// ok. now its declaration is visible and we can use it.
void f(Enum2 e) {
}
Note: It will trigger a -Wpedantic warning.
If you are using C++11, you should use their enums, which are safe to forward declare -- e.g. enum class Enum:uint8_t; (not a compiler extension).
What worked for a forward declaration of an enum for me in an Objective C .h file was look in the ProjectName-Swift.h file and see what it put, which happened to be the following:
enum SwiftEnumName : NSInteger;
I needed this forward declaration because I had a function parameter type of SwiftEnumName. And it wouldn't let me put the ProjectName-Swift.h import in the Objective C .h file.
Then in the Objective C .m file I just had the #import "ProjectName-Swift.h" in it and just used the SwiftEnum normally.
This was using Swift 4.1.2.
You'd have to either #import them anyway or create a separate header file containing only the typedef. Not importing header files in a header makes the compilation faster, but doesn't change anything else.
Why doesn't C++ support forward declaration of enums?