newguy
newguy

Reputation: 5976

in Objective C, is it possible to use a selector from outside of the class?

For example I have a method that looks like this

[self performSelectorOnMainThread:@selector(someMethod) 
                       withObject:data
                    waitUntilDone:YES];

In which "someMethod" is from another class. If it is possible, how can I do that? Also, I'd like to know how can I pass in the parameters.

Assume that someMethod is defined as:

- (void)someMethod:(NSData *)data otherArg:(NSString *)arg;

Upvotes: 1

Views: 1758

Answers (5)

rob mayoff
rob mayoff

Reputation: 385610

The message you want to send takes two parameters, and there's no variant of performSelectorOnMainThread:... that passes two parameters with the message.

The easiest way to do this is to use Grand Central Dispatch and a block. If you are sure that you will not do this on the main thread, you can do this:

dispatch_sync(dispatch_get_main_queue(), ^{
    [otherObject someMethod:myData otherArg:@"my argument"];
});

But if you run that code when you're already on the main thread, that code will deadlock - your app will hang.

If you might want to do it when you're already on the main thread, you have to be more careful to avoid deadlock. I'd do it like this:

dispatch_block_t block = ^{
    [otherObject someMethod:myData otherArg:@"my argument"];
};

if (dispatch_get_current_queue() == dispatch_get_main_queue()) {
    block();
} else {
    dispatch_sync(dispatch_get_main_queue(), block);
}

Upvotes: 0

Caleb
Caleb

Reputation: 124997

It depends. If 'self' inherits from the class that implements someMethod, then you can of course do that. But you can't send a message to an object whose class (or ancestor class) doesn't implement that method. (Well, you can, but expect an error.)

The code snippet you show is similar to:

[self someMethod:data];

except that someMethod: will run on the main thread rather than whatever thread is currently executing. Looking at it that way may help you remember that the receiver (self in this case, but it could be a pointer to any object) has to implement the message you're sending.

Upvotes: 1

rishi
rishi

Reputation: 11839

Yes you can call selector of another class as well.

If selector is class method -

[ClassName performSelectorOnMainThread:@selector(someMethod:) 
                   withObject:data
                waitUntilDone:YES];

and method signature is something like -

+ (void)someMethod:(returntype)somearg

If selector is instance method -

[classInstance performSelectorOnMainThread:@selector(someMethod:) 
                   withObject:data
                waitUntilDone:YES];

and method signature is something like -

- (void)someMethod:(returntype)somearg

Upvotes: 3

TheAmateurProgrammer
TheAmateurProgrammer

Reputation: 9392

Instead of self, you replace that with the instance of the class you want to perform the selector on.

Upvotes: 0

borrrden
borrrden

Reputation: 33421

You need to replace self with an instance of the class that defines the method. Otherwise you will get an unrecognized selector error. Also, don't forget to put a colon ( : ) after someMethod if you are sending it an argument.

Upvotes: 3

Related Questions