Reputation: 7048
I'm quite a newbie in Objective C, though I have some background in Java reflection.
Here, I have a classic class method findAll that find all the domain objects from the database. The class Univers directly inherits from DomainObject
@interface DomainObject : NSObject
- (NSString *) execute : (NSString*) method withJson:(NSString*)json;
+ (NSString*)findAll: (NSString*)json;
@end
@implementation DomainObject
- (NSString *) execute: (NSString*) method withJson:(NSString*)json{
method = [NSString stringWithFormat:@"%@%@", method, @":"];
//method is 'findAll:'
NSString* result = [ self performSelector:
NSSelectorFromString(method) withObject:json];// Error here
return result;
}
@end
The code was working when findAll was NOT a class method (ie -findAll declaration), but now I have the error : NSInvalidArgumentException -[Univers findAll:] It clearly seems that the runtime is looking for an instance method.
Any idea to find my class method ?
Upvotes: 1
Views: 1153
Reputation: 29562
Instead of calling
NSString* result = [self performSelector:NSSelectorFromString(method) withObject:json];
you need to call
NSString* result = [[self class] performSelector:NSSelectorFromString(method) withObject:json];
for class methods.
After all it's the object instance's class that supposed to be calling the method, not the instance itself.
Short explanation: NSObject
implements - (Class)class;
(not to be mistaken with + (Class)class
of similar effect, which NSObject
implements, too!) which returns the Class object of your instance object. Keep in mind that in Objective-C in addition to plain instance objects, Classes are actual objects, too: objects of type Class
, that is (vs. id
, NSObject
, …).
See the documentation for the -class
method here.
Btw, you should probably wrap your method call into an conditional block to prevent exceptions caused by calls to missing methods.
SEL selector = NSSelectorFromString(method);
if ([[self class] respondsToSelector:selector]) {
NSString* result = [[self class] performSelector:selector withObject:json];
}
In general it's a common pattern in Objective-C to call an object's class method by receiving the class object via [object class]
.
Consider this case of a class called Foo
implementing a convenience method for returning an autporeleased instance of itself (to be called via: Foo *newFoo = [Foo foo];
):
While it would certainly be possible to implement said method like this (after all we know the object's class name, right?):
+ (id)foo {
return [[[Foo alloc] init] autorelease];
}
the correct way is this:
+ (id)foo {
return [[[self alloc] init] autorelease];
}
As the first one would cause problems with polymorphism in subclasses (Such as a subclass called FooBar
, for which it should clearly be [FooBar alloc] …
, not [Foo alloc] …
. Luckily [[self class] alloc]
solves this dynamically).
While this is clearly not the right place for a thorough explanation of this (rather offtopic one might say) it's certainly worth noting/warning about, imho.
Upvotes: 5