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
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.
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.
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.
As an example, when I'm using an NSMutableDictionary, I know it inherits all the methods of NSDictionary, but how can I know/trust that it has overridden the behavior of those methods if I want to use NSDictionary methods (such as +dictionaryWithObjectsAndKeys) to create my mutable dictionary instance?
More generally, is it the Framework's responsibility to make sure subclasses don't blindly inherit methods that can potentially break instances of the subclass if used? Or is it the coder's responsibility to know not to use them? If Square inherits from Rectangle, and via inheritance I can call
Square *newSquare = [[Square alloc] init];
[newSquare setWidth:3 andHeight:6]; //instead of -(void)setSide:(int)side
I've "broken" the square and other methods which depend on width being equal to height will not work now. What are the rules of the game?
The rule would be only expose what you would allow to be override it means, put on your interface what is really public. When necessary explicitly state that when overriding an specific method call at some point [super methodName].
On your example you would override the method - (void)setWidth:(int)width andHeight:(int)height, and you would like to throw an error if width != height. Or you could also throw an error and force the user to only use - (void)setSide:(int)side.
For example you could do:
// If you want to test and accept cases when width == height
- (void)setWidth:(int)width andHeight:(int)height {
NSAssert(width == height, NSLocalizedString(#"This is a Square. Width has to be height.", nil));
[super setWidth:width andHeight:height];
// Or
[self setSide:width];
}
// Or if you want to completely prohibit the usage of the method
- (void)setWidth:(int)width andHeight:(int)height {
NSAssert(NO, NSLocalizedString(#"This is a Square! Please use - (void)setSide:(int)side method.", nil));
}
If you would like to throw some errors and warnings at compilation time, you could use on the declaration of your methods, some of the macros defined on NSObjCRuntime.h.
I wouldn't trust the parent convenience method to call your inheriting init method. For example, that dictionary method could be defined as:
+ (id)dictionaryWithObjectsAndKeys:...
{
return [[[NSDictionary alloc] initWithObjectsAndKeys:...] autorelease];
}
If that method is defined that way then it won't be even be aware of your implementation.
You'd have to create your own convenience method. Something like would be in your MyDictionary implementation:
+ (id)myDictionaryWithObjectsAndKeys:...
{
return [[[MyDictionary alloc] initWithObjectsAndKeys:...] autorelease];
}
--
Also...
You probably should inherit Rectangle from Square. Inheritance is additive. You can describe Square with one size (width), but for Rectangle you have two sizes (width, height).
I have two similar classes, MultiSlotBlock and SingleSlotBlock. They have started to share a lot of common code so I have decided to do some refactoring and pull some of the methods up to a new superclass, let's call it Block.
Now one of the methods that I pull up, simplified for the example, looks like this:
// (Block.mm)
- (void)doACommonBehaviour
{
// .. does some stuff
[self doAUniqueBehaviour];
}
The problem here is that [self doAUniqueBehaviour] is showing a warning because of course my superclass doesn't implement this method anywhere.
The two solutions I thought of don't sound great to me. One is to use a protocol (the way I am currently doing it) like so:
// (Block.mm)
- (void)doACommonBehaviour
{
// .. does some stuff
if ([self conformsToProtocol:#protocol(UniqueBehaviourProtocol)])
{
id<UniqueBehaviourProtocol> block = (id<UniqueBehaviourProtocol>)self;
[block doAUniqueBehaviour];
}
}
The other is to have a blank method body in my superclass (in this case there would be a lot) and just return doesNotRespondToSelector.
Something is tingling at the back of my mind that I should be using the Strategy Pattern, but I might be way off, and I haven't thought through how that would be implemented.
Any ideas? Thanks.
EDIT: I know for a fact that doAUniqueBehaviour will be implemented in all subclasses, it is just the implementation that will differ.
The superclass should not know about its subclasses. You should implement the
- (void)doACommonBehaviour method in every subclass and there:
- (void)doACommonBehaviour
{
[super doACommonBehaviour];
[self doAUniqueBehaviour];
}
EDIT - clarification:
If all the subclasses are going to implement -doAUniqueBehaviour then it should be implemented in the superclass (even empty) and each subclass will override it to its needs.
If subclass1 implements -doAUniqueBehaviour1, subclass2 implements -doAUniqueBehaviour2 etc then do what I propose above; eg. in subclass1:
- (void)doACommonBehaviour
{
[super doACommonBehaviour];
[self doAUniqueBehaviour1];
}
There is not such concept as abstract class in Objective-C. In order to avoid the warning, you have to provide a default implementation in your base class. Usually, this implementation will throw a doesNotRespondToSelector error at runtime:
- (id)someMethod:(SomeObject*)blah
[self doesNotRecognizeSelector:_cmd];
return nil;
}
Note: the _cmd argument is the invoked selector.
#Dimitri's suggestion will work, but instead of forcing each subclass to implement the same method, you can declare it once in Block, and just above that method (in the implementation file, not header) declare the unique method like so:
- (void) doUniqueBehaviour { }
- (void) doCommonBehaviour {
// any common code you need
[self doUniqueBehaviour];
}
This will prevent any compiler warnings, and you can override -doUniqueBehaviour in subclasses as you like. It also avoids code duplication and reduces the potential for changing the code in one subclass but not another. Plus, you don't need a separate protocol, and dynamic typing is preserved.