Reputation: 4844
I want to create a controller that depends on the class of a given instance of a model
-(BaseController *)getControllerForModel:(Model *)model
{
BaseController *controller = nil;
Class controllerClass = [BaseController class]; //the default value
//find the right controller
if ([model isMemberOfClass:[ModelClass1 class]])
controllerClass = [ConcreteController1 class];
else if ([model isMemberOfClass:[ModelClass2 class]])
controllerClass = [ConcreteController2 class];
else if ([model isMemberOfClass:[ModelClass3 class]])
controllerClass = [ConcreteController3 class];
...
else if ([model isMemberOfClass:[ModelClassX class]])
controllerClass = [ConcreteControllerX class];
else
Trace(TRACELEVEL_WARNING, @"Unrecognized model type: %@", NSStringFromClass([model class]));
//Now instantiate it with the model
controller = [[[controllerClass alloc] initWithModel:model] autorelease];
return slotController;
}
I want to find a more flexible solution to this and thought of having a dictionary, which maps Model-Classes to Controller-Classes and then NSClassFromString
could give me the right instance.
My question is this: Is NSClassFromString
using much of my applications performance if i use it several times (say, 100 times at once)? Or would it be about as fast as the above approach?
Upvotes: 2
Views: 1316
Reputation: 71
Remember that nib/xib files store the file's owner class as a string, so nib instantiation requires a lookup by string. This makes it highly unlikely that Apple would use a grossly inefficient lookup. (Also highly unlikely they would implement efficient lookup, keep it private, implement a separate inefficient lookup and expose that.)
Upvotes: 0
Reputation: 53659
A Class is an id, and as such can be added to an NSDictionary. You should try the following:
mModelToControllerMap = [[NSDictionary alloc] initWithObjectsAndKeys:
[ConcreteController1 class] , [ModelClass1 class] ,
[ConcreteController2 class] , [ModelClass2 class] ,
...
nil];
Then later:
controllerClass = [mModelToControllerMap objectForKey:[modelInstance class]];
if ( controllerClass ) ...
else ...
If you make it a mutable dictionary, you can then have controllers register for the models they want instead of forcing the base class to be aware of all derived classes.
And a direct answer. At worst, NSClassFromString may need to iterate through all classes to find a match. It could also be a dictionary lookup, but the implementation is not documented and should not be relied on. While doing it a few hundred times probably isn't too bad, there are better ways.
Upvotes: 3
Reputation: 162712
Generally, use of isMemberOfClass:
in such a fashion indicates an architectural issue.
In this case, why can't the various Model
classes simply implement a +controllerClass
method?
I can understand Nikolai's desire to maintain the layering of Controller on top of Model without the Model having knowledge of the Controller. However, my experience is that any control layer that has such type specific knowledge of the Model quickly destroys that isolation anyway; the model layer quickly evolves behaviors that are controller specific.
Thus, the added complexity injected by attempting to maintain that separation just isn't worth it.
Upvotes: 5
Reputation: 7255
NSStringFromClass
shouldn't be much more expensive. In fact, in your case you could use it much more effectively. I don't know your exact class naming convention, but using a methof like this could be much smaller and faster:
NSString * modelClassName = NSStringFromClass([model class]);
// get the suffix of class name
// for example, '3' in 'ModelClass3'
NSString * suffix = [modelClassName substringFromIndex:10];
// create the controller name
NSString * controllerName = [NSString stringWithFormat:@"ConcreteController%@", suffix];
/* do something if name is not valid */
controllerClass = NSClassFromString(controllerName);
as bbum suggested you could also make this a method on a common parent of the model classes.
Upvotes: 2
Reputation: 81858
If you're really concerned about performance, you could cache the results of the NSClassFromString
and put them in a dictionary.
On the other hand, that's probably pretty much what NSClassFromString
really does (a map lookup). So I'd say it's much faster that the 100x if approach.
But anyway: Just give it a try, as with all performance issues.
Upvotes: 2