I'm using Cocos2D for iOS, but you most likely don't have to be familiar with Cocos2D, just Obj-C to answer my question.
I have an enemy class while developing this game that I've used for a long time, but now it's reached a point of complexity and I'll need to do something about to make it more organized and readable.
The way it works currently is this: I have the enemy class that I allocate a certain number of times and insert into a mutable array. I can then flip through that mutable array whenever. When the enemy class is allocated, it is also directed to initialize and pass a string of the enemy name. In it's init there are a series of if/if else statements that check the enemy name and set the right values for it. This worked just fine, except design-wise it got very confusing to look through all those names when I added more and more enemies.
What I want to do now is subclass off of my enemy class of all the different enemies. I'll need to access the enemy's properties just like I would other kinds of enemies from that class.
Right now in the enemy class init I have something like:
-(id) initWithEnemy:(NSString *)kind {
if([kind isEqualToString:#"enemyName"]){
//set values
}
else if([kind isEqualToString:#"anotherEnemyName"]){
//set values
}
//etc, etc..
}
Now I want to have this set values stuff happen in other files. One, or a set of header/main files for each enemy. So inside initWithEnemy, I was thinking maybe I could allocate an enemy name class from the "kind" string that's passed. Not sure if I could use NSClassFromString. I've experimented with it a bit, but I'm not really sure how to access the class properties the way I did before. Even if I did access the properties the same way I did before, does that mean all the enemy name classes will have to have all the same amount of properties?
You can split your enemies into an abstract base class with concrete sub-classes - that is a good approach. Be mindful though, that it can often be better to use composition over inheritance - this is where you inject objects into a holder class to model something. Otherwise you might run into the problem where you have an enemy that's both a 'Monster' and a 'Wizard' and the single inheritance chain doesn't allow that.
There are two design patterns that seem appropriate here - they both focus on decoupling complex instantiation rules from the class itself. One is the factory pattern and the other is the builder pattern. If you split into a class hierarchy the former will be appropriate, otherwise the latter.
Sorry, can't provide more examples - writing this on an iPad, and on the way out the door.
Instead of strings, declare an enum
typedef enum {
kEnemyInvalid = 0,
kEnemyName1,
kEnemyName2,
[...]
} EnemyType;
Create an Enemy class with the global properties for all enemy types.
Create necessary enemy subclasses for each type. It's possible that a class will cover more than one enemy types.
Create a function (possibly a class method)
Class EnemyClassFromEnemyType(EnemyType type) {
switch (type) {
case kEnemyName1:
return [EnemyName1 class];
case kEnemyName2:
return [EnemyName2 class];
default:
return Nil;
}
}
This function makes a connection between the enemy type and the class that implements it. There are ways how to make it more pretty, my preferred way is using X-Macros.
And now let's create a factory method to create the enemies
+ (Enemy*)createEnemyWithType:(EnemyType*)enemyType {
Class enemyClass = EnemyClassFromEnemyType(enemyType);
return [[enemyClass alloc] initWithType:enemyType];
}
The same using X-Macros
Header file
#define ENEMY_DEFINITIONS \
ENEMY_DEFINITION(kEnemyInvalid, = 0, Nil) \
ENEMY_DEFINITION(kEnemyName1,, [EnemyName1 class]) \
ENEMY_DEFINITION(kEnemyName2,, [EnemyName2 class])
#define ENEMY_DEFINITION(name, intValue, enemyClass) name intValue,
/**
* Your enum declaration.
*/
typedef enum {
ENEMY_DEFINITIONS
} EnemyType;
#undef ENEMY_DEFINITION
Class EnemyClassFromEnemyType(EnemyType type);
NSString* NSStringFromEnemyType(EnemyType type);
Implementation file
#define ENEMY_DEFINITION(name, intValue, enemyClass) [name] = ##name,
NSString* EnemyTypeStringTable[] = {
ENEMY_DEFINITIONS
}
#undef ENEMY_DEFINITION
NSString* NSStringFromEnemyType(EnemyType type) {
return EnemyTypeStringTable[type]
}
#define ENEMY_DEFINITION(name, intValue, enemyClass) classTable[name] = enemyClass;
Class EnemyClassFromEnemyType(EnemyType type) {
static Class* classTable = nil;
if (classTable == nil) {
classTable = malloc(sizeof(Class) * sizeof(EnemyTypeStringTable) / sizeof(NSString*));
ENEMY_DEFINITIONS
}
return classTable[type];
}
#undef ENEMY_DEFINITION
The beauty of using X-Macros technique is that you have everything in one place, you can easily add more types without changing anything else. You get something like Java enums because the enums can have properties.
Related
As a part of my model I have a class called "Slide" which has two children : "QuizzSlide" and "ImageSlide". I also have another class called "SlideView" (which is part of my views) which has two children "QuizzSlideView" and "ImageSlideView".
Now what I want to do is go through a collection of Slides and create the correct SlideViews to display them. Problem is, to instantiate a SlideView I need to know the type of the Slide. QuizzSlide should create a QuizzSlideView and ImageSlide should create an ImageSlideView. I see two options :
Introspection. I don't like introspection because it means the class that builds the object has to exhaustively list the types of objects that it can deal with. If I add another type of Slides down the line, I have to modify the builder class.
Making the Slide create its associated View. So I'd have a function getView that gets overridden by every child of Slide to create the correct View for that slide. This would work and it would make maintenance easier but it makes a horrible mess of the program as the model shouldn't contain references to the views it represents.
That's pretty much it. Do I have any other options? Any ideas on how to uncouple my models from my views, build the correct views depending on the model types AND avoid introspection?
Thanks
Why not a Factory method createView() in the Slide class which, when implemented in QuizzSlide returns a QuizzSlideView and in ImageSlide returns an ImageSlideView pointing to the proper model.
This reminds me of the Iterator pattern, where CreateIterator() is the factory method.
Iterator pattern in UML http://www.silversoft.net/docs/dp/hires/Pictures/itera040.gif
I think the introspection method is best, however if you are concerned about having to modify the code if you introduce new classes (a legitimate concern) then I would make it table driven, which would limit the amount of new code required.
(Note I have not tested this code):
static struct {
Class slideClass;
Class viewClass;
} _slideMap[] = {
{ [QuizzSlide class], [QuizzView class] },
{ [ImageSlide class], [ImageView class] }
};
#define NUM_SLIDE_MAPS (sizeof(_slideMap) / sizeof(_slideMap[0]))
Then use:
for (id slide in _slides) {
UIView *view = nil;
CGRect frame = ...;
for (unsigned i = 0; i < NUM_SLIDE_MAPS && !view; i++)
if ([slide isKindofClass:_slideMap[i].slideClass])
view = [[_slideMap[i].viewClass alloc] initWithFrame:frame];
NSAssert(view, #"Missing slide/view map entry for class %#", NSStringFromClass([slide class]));
}
Note: It's possible this code won't compile as the expression [QuizzSlide class] is not a constant expression, in which case you will be forced to create the array at runtime, using a dispatch_once() statement or some such.
You might also be able to use an NSDictionary to hold the mapping between the slide and view classes and get even quicker look-up performance.
Hello all,
I've been working on some enumeration routines in Objective-C that perform object introspection. In particular, I'm fast enumerating an NSSet and making sure that the objects therein belong to class BBBallView (an fairly unfortunate name, I agree) before tweaking their properties and/or calling their methods.
In order to make the parser and compiler happy, however, I end up casting the object to its class on every single line; moreover, in order to access its properties, the object's cast has to be in parentheses, otherwise dot notation won't work. This leads to somewhat messy code:
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( !((BBBallView *)otherBall).isEnlarged ) {
CGRect otherFrame = ((BBBallView *)otherBall).frame;
/* ... */
}
}
}
Is there any way to tell the compiler something like "at this point I know that otherBall is a BBBallView, so stop telling me it doesn't respond to these selectors and properties"? That way, one could just write:
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( !otherBall.isEnlarged ) {
CGRect otherFrame = otherBall.frame;
/* ... */
}
}
}
and so on.
I tried otherBall = (BBBallView *)otherBall but "fast enumeration variables can't be modified in ARC by default". Changing the enumeration variable to __strong id fixes it, but doesn't help the fact that any subsequent line gives out errors such as "property isEnlarged not found on object of type 'const __strong id'", so I'm back to square one.
I'm not even sure why exactly this happens: shouldn't the compiler stay out of the way when an variable is of type id? In any case, the whole ordeal particularly messy in methods that need to perform several calculations on objects' properties, as it quickly becomes unreadable with all those parentheses.
Is there any way around this?
Thanks in advance!
You can either create a local temp with the correct type or just not use dot notation.
local temp
for (UIView *view in self.gameField.subviews) {
if ([view isKindOfClass:[BBBallView class]]) {
BBBallView *ballView = view;
if (!ballView.isEnlarged) {
CGRect otherFrame = ballView.frame;
/* ... */
}
}
}
don't use dot notation
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( ![otherBall isEnlarged]) {
CGRect otherFrame = [otherBall frame];
/* ... */
}
}
}
If I was only doing a couple of things I would be tempted to not use dot notation. If it became awkward to read and there was a lot of accesses then I would consider local temp
I think you're struggling because the logic appears misplaced. The language is fighting you because of your program's structure, not because the language is deficient.
Is the parent type of subviews really appropriate? Or are you violating the Liskov Substitution Principle by stuffing a round object in a square type?
You can also ask if is it really appropriate to examine the internals of BBBallView logic from outside? Can you move the logic into the appropriate class?
I was going through and replacing #synthesized(self) locks w/ this method
void _ThreadsafeInit(Class theClassToInit, void *volatile *theVariableItLivesIn, void(^InitBlock)(void))
{
//this is what super does :X
struct objc_super mySuper = {
.receiver = (id)theClassToInit,
.super_class = class_getSuperclass(theClassToInit)
};
id (*objc_superAllocTyped)(struct objc_super *, SEL, NSZone *) = (void *)&objc_msgSendSuper;
// id (*objc_superAllocTyped)(id objc_super, SEL, NSZone *) = (void *)&objc_msgSend;
do {
id temp = [(*objc_superAllocTyped)(&mySuper /*theClassToInit*/, #selector(allocWithZone:), NULL) init];//get superclass in case alloc is blocked in this class;
if(OSAtomicCompareAndSwapPtrBarrier(0x0, temp, theVariableItLivesIn)) { //atomic operation forces synchronization
if( InitBlock != NULL ) {
InitBlock(); //only the thread that succesfully set sharedInstance pointer gets here
}
break;
}
else
{
[temp release]; //any thread that fails to set sharedInstance needs to clean up after itself
}
} while (*theVariableItLivesIn == NULL);
}
which while a bit more verbose exhibits significantly better performance in non-contested cases
along with this little macro (excuse poor formatting, it's very simple). To allow the block to be declared after the initial nil check, looks to help LLVM keep the "already initialized" path extremely fast. That's the only one I care about.
#define ThreadsafeFastInit(theClassToInit, theVariableToStoreItIn, aVoidBlockToRunAfterInit) if( theVariableToStoreItIn == nil) { _ThreadsafeInitWithBlock(theClassToInit, (void *)&theVariableToStoreItIn, aVoidBlockToRunAfterInit); }
So initially implemented it using the commented out sections for objc_superAllocTyped (actually first using [theClassToInit allocWithZone:NULL], which was definitely the best approach :) ), which worked great until I realized that most of the singletons in the project had overridden allocWithZone to return the singleton method... infinite loop. So I figured using objc_msgSendSuper should sort it out quickly, but I get this error.
[51431:17c03] +[DataUtils allocWithZone:]: unrecognized selector sent to class 0x4f9584
The error doesn't seem to be related to the actual problem, as...
(lldb) po 0x4f9584
$1 = 5215620 DataUtils
(lldb) print (BOOL)[$1 respondsToSelector:#selector(allocWithZone:)]
(BOOL) $2 = YES
So I'm definitely missing something... I compared to assembly generated by a [super allocWithZone:NULL] method in an empty class... almost identical except for the functions called have different names (maybe just using different symbols, no idea, can't read it that well).
Any ideas? I can use class_getClassMethod on the superclass and call the IMP directly, but I'm trying to be reasonable in my abuse of the runtime :)
Alright, this wasn't actually that tricky once I recalled that the meta class contains all of the method information for a Class instance obtained via -[self class] or +[self] -> thanks http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html
This error occurred because I was asking the runtime to look up the method in NSObject's set of instance methods, which obviously doesn't contain allocWithZone: . The mistake in the error log presumably originated because the receiver was a metaclass instance, and Apple has their interns implement error logs.
so while with a normal instance method call via objc_msgSendSuper, you would pass a metaclass instance as objc_super.super_class, to invoke a class method, the metaclass itself is needed (everything is one level up).
Example, and a diagram that helped me understand this - (http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html)
struct objc_super mySuper;
mySuper.receiver = theClassToInit; //this is our receiver, no doubt about it
//either grab the super class and get its metaclass
mySuper.super_class = object_getClass( class_getSuperclass( theClassToInit ) );
//or grab the metaclass, and get its super class, this is the exact same object
mySuper.super_class = class_getSuperclass( object_getClass( theClassToInit ) );
Then the message can be resolved correctly. Makes perfect sense now that I started paying attention :P
Anyways, now that I found my mistake I feel like I've leveled up my Objc runtime understanding. I was also able to fix an architectural mistake made two years ago by someone I never met without having to modifying and re-test dozens of classes across 3 projects and 2 static libraries (God I love Objective-C). Replacing the #synchronized construct with a simple function call also halved the compiled code size of those methods. As a bonus, all our singleton accessors are now (more) threadsafe, because the performance cost for doing so is now negligible. Methods which naively re-fetched the singleton object multiple times (or in loops) have seen a huge speedup now that they don't have to acquire and release a mutex multiple times per invocation. All in all I'm very happy it all worked as I'd hoped.
I made a "normal" Objective-C method for this on a category of NSObject, which will work for both instance and Class objects to allow you to invoke a superclass's implementation of a message externally. Warning: This is only for fun, or unit tests, or swizzled methods, or maybe a really cool game.
#implementation NSObject (Convenience)
-(id)performSelector:(SEL)selector asClass:(Class)class
{
struct objc_super mySuper = {
.receiver = self,
.super_class = class_isMetaClass(object_getClass(self)) //check if we are an instance or Class
? object_getClass(class) //if we are a Class, we need to send our metaclass (our Class's Class)
: class //if we are an instance, we need to send our Class (which we already have)
};
id (*objc_superAllocTyped)(struct objc_super *, SEL) = (void *)&objc_msgSendSuper; //cast our pointer so the compiler can sort out the ABI
return (*objc_superAllocTyped)(&mySuper, selector);
}
so
[self performSelector:#selector(dealloc) asClass:[self superclass]];
would be equivalent to
[super dealloc];
Carry on runtime explorers! Don't let the naysayers drag you into their land of handwaving and black magik boxes, it's hard to make uncompromisingly awesome programs there*.
*Please enjoy the Objective-C runtime responsibly. Consult with your QA team for any bugs lasting more than four hours.
I'm looking for advice on whether or not this is a good practice. I apologize for the long form explanation. I have a large grid of x,y coordinates. The grid is occupied by objects of varying classes, all with different methods and data. When a user touches a grid coordinate, I'm looking for the cleanest way to route my program to the proper method, dependent on the object type.
I'll use shapes as an easy way to explain what I'm doing. Say I have 2 classes, Circle and Square both with a parent class of Shape.
I'm adding objects of Circle class and Square class to an NSMutableArray called shapeManager. When a user touches the grid I want to figure out the object type for that coordinate so I can route to the appropriate method.
for (Shape *shape in shapeManager) {
if (shape.type == kCircle) {
[self circleSelected:shape];
}
}
-(void)circleSelected:(circle *)circle { }
Am I recasting the pointer as a different class when I do this? Are there any downsides to this? I'm just looking for a good way to handle a touch event on a grid, when the object that lives at that coordinate is unknown and of multiple possible classes.
The downside to your approach comes if you add another Shape - you end up having to change this code. The other approach is to add a method, say userSelected, to your Shape class and have each subclass override this method to do whatever is appropriate for the kind of shape they represent.
In this other approach your loop becomes:
for(Shape *shape in shapeManager)
[shape userSelected];
And, for example, Circle gains a method:
#implementation Circle
// override Shape's userSelected and do what a circle needs to do
- (void) userSelected
{
...
}
Which approach you choose is up to you, there is no right answer per se, but object-oriented style usually favours the latter.
Comment Followup
To go from a child to a parent you do not need a cast, but can include one - this is a fundamental plank of inheritance-based object-oriented languages like Obj-C.
Going the other way, from parent to child, in Obj-C (a) requires a cast and (b) should be protected by a check - both because you don't know which, if any, of the children you have. In Obj-C (a) just tells the compiler you think you know and it should trust you, (b) is you checking to make sure!
You do (b) with [<obj> isKindOfClass:[<classname> class] which tests if <obj> is of type <classname> or any of its children; or you can use isMemberOfClass which tests if <obj> is of type <classname> but not any of its children. The former is more common to allow for easy expansion (e.g. you may start off with Rectangle being a Shape and later introduce Square being a Rectangle; a test for isMemberOfClass:[Rectangle class] would be YES for both Rectangle and Square while isKindOfClass:[Rectangle class] is only YES for Rectangle).
Explicit testing is commonly not required as method dispatch often subsumes it - as in [shape userSelected] above which will call the appropriate implementation of userSelected based on the actual type of shape at runtime. When explicit testing is required using tests and casts is the way to do it.
And yes, collections of mixed type are common, indeed they are another of the planks of inheritance-based object-oriented languages like Obj-C.
[Note: What Obj-C lacks which a number of other languages have is a way to limit what a collection may contain. E.g. an NSMutableArray can contain any object, while in your case it might be beneficial to be able to say NSMutableArray of Shape to limit it to just Shape and its subclasses. C#, Ada, and even C++ (in as much as it enforces anything) all provide this. If you need to you can do it yourself in Obj-C, see this answer.]
All classes that derive from NSObject inherit a method called isMemberOfClass: that will test for class membership using introspection. You may find this useful for your purposes.
for (Shape *shape in shapeManager) {
if ([shape isMemberOfClass:[Circle class]]) {
[self circleSelected:(Circle*)shape];
}
else if ([shape isMemberOfClass:[Square class]]} {
[self squareSelected:(Square*)shape];
}
}
There is also an isKindOfClass: method that does a similar test, but will also return true if the receiving object is a subclass of the class you are testing against.
How about implementing 'selected' method in the subclasses of Shape, which are Circle and Square class. Then the object can call 'selected' method directly.
for (Shape *shape in shapeManager) {
[self selected];
}
Circle implementation
#interface Circle: Shape
{
}
#implementation Circle
-(void)selected
{
// do your circle select stuff here
}
#end
Square implementation
#interface Square: Shape
{
}
#implementation Square
-(void)selected
{
// do your square select stuff here
}
#end
What would be a nice pattern in Objective-C for class variables that can be "overridden" by subclasses?
Regular Class variables are usually simulated in Objective-C using a file-local static variables together with exposed accessors defined as Class methods.
However, this, as any Class variables, means the value is shared between the class and all its subclasses. Sometimes, it's interesting for the subclass to change the value for itself only. This is typically the case when Class variables are used for configuration.
Here is an example: in some iOS App, I have many objects of a given common abstract superclass (Annotation) that come in a number of concrete variations (subclasses). All annotations are represented graphically with a label, and the label color must reflect the specific kind (subclass) of its annotation. So all Foo annotations must have a green label, and all Bar annotations must have a blue label. Storing the label color in each instance would be wasteful (and in reality, perhaps impossible as I have many objects, and actual configuration data - common to each instance - is far larger than a single color).
At runtime, the user could decide that all Foo annotations now will have a red label. And so on.
Since in Objective-C, Classes are actual objects, this calls for storing the Foo label color in the Foo class object. But is that even possible? What would be a good pattern for this kind of things? Of course, it's possible to define some sort of global dictionary mapping the class to its configuration value, but that would be kind of ugly.
Of course, it's possible to define some sort of global dictionary mapping the class to its configuration value, but that would be kind of ugly.
Why do you think this would be ugly? It is a very simple approach since you can use [self className] as the key in the dictionary. It is also easy to make it persistent since you can simply store the dictionary in NSUserDefaults (as long as it contains only property-list objects). You could also have each class default to its superclass's values by calling the superclass method until you find a class with a value.
+ (id)classConfigurationForKey:(NSString *)key {
if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
Class c = [self class];
id value = nil;
while(value == nil) {
NSDictionary *classConfig = [_configurationDict objectForKey:[c className]];
if(classConfig) {
value = [classConfig objectForKey:key];
}
c = [c superclass];
}
return value;
}
+ (void)setClassConfiguration:(id)value forKey:(NSString *)key {
if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
NSMutableDictionary *classConfig = [_configurationDict objectForKey:[self className]];
if(classConfig == nil) {
classConfig = [NSMutableDictionary dictionary];
[_configurationDict setObject:classConfig forKey:[self className]];
}
[classConfig setObject:value forKey:key];
}
This implementation provides no checking to make sure you don't go over the top superclass, so you will need to ensure that there is a value for that class to avoid an infinite loop.
If you want to store objects which can't be stored in a property list, you can use a method to convert back and forth when you access the dictionary. Here is an example for accessing the labelColor property, which is a UIColor object.
+ (UIColor *)classLabelColor {
NSData *data = [self classConfigurationForKey:#"labelColor"];
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
+ (void)setClassLabelColor:(UIColor *)color {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:color];
[self setClassConfiguration:data forKey:#"labelColor"];
}
my answer here may help:
What is the recommended method of styling an iOS app?
in that case, your annotation just holds a reference to a style (e.g. you need only one per style), and the size of a pointer for an entire style is not bad. either way, that post may give you some ideas.
Update
Jean-Denis Muys: That addresses the sample use case of my question, but not my question itself (a pattern to simulate class instance variables).
you're right, i didn't know how closely your example modeled your problem and i considered commenting on that.
for a more general and reusable solution, i'd probably just write a threadsafe global dictionary if your global data is nontrivial (as you mentioned in your OP). you could either populate it in +initialize or lazily by introducing a class method. then you could add a few categories to NSObject to access and mutate the static data -- do this for syntactical ease.
i suppose the good thing about that approach is that you can reuse it in any program (even though it may appear ugly or complex to write). if that's too much locking, then you may want to divide dictionaries by prefixes or create a simple thread safe dictionary which your class holds a reference to -- you can then synthesize an instance variable via the objc runtime to store it and declare an instance method to access it. the class method would still have to use the global data interface directly.