ximmyxiao
ximmyxiao

Reputation: 2819

How to judge a selector is contained in a protocol in objc? thanks

I want to forwarding all UITableViewDelegate method to another object for some reason 。 Here is the code I wrote , but because there are so many methods in UITableViewDelegate.I have to write to many if else compare for each method.

- (id)forwardingTargetForSelector:(SEL)aSelector
{    
    NSString* selector = NSStringFromSelector(aSelector);
    if ([selector isEqualToString:@"tableView:didSelectRowAtIndexPath:"])
    {
        return self.outDelegate;
    }
    else
    {
        return [super forwardingTargetForSelector:aSelector];

    }
}

And I think there is a better solution to do this.can I do it like below,how to test aSelector is Defined in aProtocol or not

- (id)forwardingTargetForSelector:(SEL)aSelector
{    
    if (**aSelector is Defined in aProtocol**)
    {
        return self.outDelegate;
    }
    else
    {
        return [super forwardingTargetForSelector:aSelector];

    }
}

Upvotes: 2

Views: 543

Answers (5)

malhal
malhal

Reputation: 30791

In UIKit, Apple do this in UIUserNotificationRestrictedAlertViewProxy's respondsToSelector to check isAlertViewDelegateMethod but I have modified the code to work with the UITableViewDelegate so here you go:

BOOL isTableViewDelegateMethod(SEL selector) {
    struct objc_method_description desc;
    desc = protocol_getMethodDescription(@protocol(UITableViewDelegate), selector, NO, YES);
    if(desc.name){
        return YES;
    }
    desc = protocol_getMethodDescription(@protocol(UITableViewDelegate), selector, YES, YES);
    if(desc.name){
        return YES;
    }
    return NO;
}

- (id)forwardingTargetForSelector:(SEL)aSelector
{    
    if (isTableViewDelegateMethod(aSelector))
    {
        return self.outDelegate;
    }
    else
    {
        return [super forwardingTargetForSelector:aSelector];

    }
}

And you may want to also check UITableViewDataSource since table views have two delegates.

Upvotes: 0

stonesam92
stonesam92

Reputation: 4457

You can get a C array of the methods in a protocol using protocol_copyMethodDescriptionList:

int numOfMethods;
struct objc_method_description * method_description_list;
method_description_list = protocol_copyMethodDescriptionList(@protocol(protocolName), 
    YES, YES, &numOfMethods)

The number of descriptions in the array is now stored in the numOfMethods variable. You can then iterate through this array and check whether the selector for each method is equal to the current selector using == rather than converting the selectors to strings:

for (int i=0; i<numOfMethods; i++) {
    if (aSelector == method_description_list[i].name) 
        //forward to other delegate
    else
        return [super forwardingTargetForSelector:aSelector];
}

Note that you will need to do free(method_description_list) to reclaim the memory it occupies once you are done with it.

There is no point in recreating and freeing it every time forwardingTargetForSelector: is called, so you might want to do something like turning it into an iVar and creating it in init, and then freeing it in dealloc, since the protocol is very unlikely to change over the lifetime of this object

Upvotes: 2

Bharath Vankireddy
Bharath Vankireddy

Reputation: 932

When you want perform this kind of forwardInvocation and delegate method validation you can use "respondToSelector" and "conformsToProtocol" methods and do the respective ForwardInvocation process.

Upvotes: 0

Sanjay Mohnani
Sanjay Mohnani

Reputation: 5967

You can use respondsToSelector: to check if a delegate has the selector

Also, you could use conformsToProtocol: in combination with respondsToSelector: as -

if([delegate conformsToProtocol:@protocol(MyProtocol)] && [delegate respondsToSelector: @selector(aMethod)])
    {
        //send message;
    }

Upvotes: 1

Mayur Deshmukh
Mayur Deshmukh

Reputation: 1169

Check like this -

if([delegate conformsToProtocol:@protocol(yourProtocolName)])
{
    //Do Something
}

Upvotes: 0

Related Questions