views:

384

answers:

5

Suppose I have Objective C interface SomeClass which has a class method called someMethod:

@interface SomeClass : NSObject {
}

+ (id)someMethod;
@end

In some other interface I want to have a helper method that would dynamically invoke someMethod on a class like this:

[someOtherObject invokeSelector:@selector(someMethod) forClass:[SomeClass class];

What should be the implementation for invokeSelector? Is it possible at all?

- (void)invokeSelector:(SEL)aSelector forClass:(Class)aClass {
   // ???
}
+2  A: 

You shouldn't implement this yourself.

The NSObject Protocol has a performSelector: method that does exactly this.

Ben S
Type Class is not NSObject. It doesn't have performSelector method
Greg
Do `Class` objects implement the `NSObject` protocol?
mipadi
How are you creating an object that isn't an NSObject? From the top of the page of the link I give: "The NSObject protocol groups methods that are fundamental to all Objective-C objects."
Ben S
@Ben S: He's trying to invoke a class method. `Class` objects don't descend from `NSObject`.
mipadi
@mipadi: You're absolutely right. Do you know why it works nevertheless?
Greg
No. The Objective-C `Object` (defined in `/usr/include/objc/Object.h`) defines a perform: method with the same signature. A `Class` object might descend from `Object`, but even that wouldn't explain it; and I haven't found anything in the Foundation framework that monkeypatches `Class` to respond to `performSelector:`.
mipadi
In Objective-C classes are objects, direct subclasses of NSObject. Every instance method defined on NSObject will work on a class.
Mike Abdullah
@Mike: Yes, but a `Class` *object* doesn't descend from `NSObject`.
mipadi
+1  A: 

Is this built-in method what you want?

id objc_msgSend(id theReceiver, SEL theSelector, ...)

(See the runtime reference docs for this function.)

vanja.
From your link: "This reference is useful primarily for developing bridge layers between Objective-C and other languages, or for low-level debugging. You typically do not need to use the Objective-C runtime library directly when programming in Objective-C."
Ben S
But isn't avoiding built-in checks and balances the whole point of dynamically sending messages?
vanja.
Never mind; didn't notice that it wasn't a subclass of NSObject.
Chris Long
I think this is the best option then.
Chris Long
+7  A: 

Instead of:

[someOtherObject invokeSelector:@selector(someMethod) forClass:[SomeClass class];

call:

[[SomeClass class] performSelector:@selector(someMethod)];

Example (using GNUstep ...)

file A.h

#import <Foundation/Foundation.h>
@interface A : NSObject {}

-(NSString* ) description;
+(NSString*)action;
@end

file A.m

#import <Foundation/Foundation.h>
#import "A.h"

@implementation A

- (NSString *) description
{
    return [NSString stringWithString: @"A"];
}

+(NSString*)action
{
    return [NSString stringWithString:@"A::action"];
}

@end

Somewhere else:

A * a = [[A class] performSelector:@selector(action)];
NSLog(@"%@",a);

Output:

2009-11-22 23:32:41.974 abc[3200] A::action
stefanB
I knew I could use performSelector on NSObject. However, I was confused because I thought the type Class didn't have performSelector method. I didn't bother to try.
Greg
Code Sense doesn't suggest `performSelector` for `[SomeClass class]` experssion.
Greg
I'm not in front of my Mac, so I tried on Linux with GNUStep and it works ... :)
stefanB
His class doesn't implement NSObject.
vanja.
True, but it's a simple fix to get the `performSelector` functionality
stefanB
A: 

Why are you writing your own root class?

NSResponder
That's a mistake. I edited my question.
Greg
+1  A: 

In Objective-C, classes are objects as well. The class objects are treated differently, however, as they can call the instance methods of their root class (NSObject or NSProxy in Cocoa).

So it's possible to use all the instance methods defined in NSObject on class objects as well and the right way to dynamically invoke a class method is:

[aClass performSelector:@selector(aSelector)];

The apple docs are a bit more specific.

Adrian