Objective C : Given a Class id, can I check if this class implements a certain protocol? Or has a certain selector?
Asked Answered
M

2

40

I want to use this for an object factory: Given a string, create a Class, and if this Class supports a protocol (with a Create() method) then alloc the class and call Create.

Mariko answered 26/2, 2010 at 20:39 Comment(0)
H
15
Class klass = NSClassFromString(classname);
if ([klass instancesRespondToSelector:@selector(create)]) {
  [[klass alloc] create];
}

May I, however, point out just how many awful Objective-C rules you're breaking by doing the above? For example, you should never be calling methods on an allocated-but-not-initialized instance. The Xcode Static Analyzer will give you all sorts of warnings about memory leaks.

A better option would be this:

[[[klass alloc] init] create];

But you seem to imply that you don't want to call init.

You could consider a class method: [klass create], which would return a non-owned instance of klass. Then you'd just check [klass respondsToSelector:@selector(create)] before calling it.

Hammers answered 26/2, 2010 at 20:47 Comment(2)
Thanks. You're right, the Create method should be a class method. I think this is usually how object factories are designed.Mariko
This is not the best answer. Chuck is better.Dine
D
272
NSString *className; //assume this exists
Class class = NSClassFromString(className);
if ([class conformsToProtocol:@protocol(SomeProtocol)]) {
    id instance = [[class alloc] init];
    [instance create];
}
Doorpost answered 26/2, 2010 at 20:53 Comment(3)
He asked two questions in his title :)Durrett
One step further: id<SomeProtocol> instance = [[class alloc] init]Broom
If you don't have or know the class name, then use [instance class] or NSStringFromClass([instance class])Mealworm
H
15
Class klass = NSClassFromString(classname);
if ([klass instancesRespondToSelector:@selector(create)]) {
  [[klass alloc] create];
}

May I, however, point out just how many awful Objective-C rules you're breaking by doing the above? For example, you should never be calling methods on an allocated-but-not-initialized instance. The Xcode Static Analyzer will give you all sorts of warnings about memory leaks.

A better option would be this:

[[[klass alloc] init] create];

But you seem to imply that you don't want to call init.

You could consider a class method: [klass create], which would return a non-owned instance of klass. Then you'd just check [klass respondsToSelector:@selector(create)] before calling it.

Hammers answered 26/2, 2010 at 20:47 Comment(2)
Thanks. You're right, the Create method should be a class method. I think this is usually how object factories are designed.Mariko
This is not the best answer. Chuck is better.Dine

© 2022 - 2024 — McMap. All rights reserved.