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?
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.
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.
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.
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.
精彩评论