Cast an instance of a class to a @protocol in Objective-C

36,616

Solution 1

The correct way to do this is to do:

if ([self.myViewController conformsToProtocol:@protocol(MyProtocol)])
{
        UIViewController <MyProtocol> *vc = (UIViewController <MyProtocol> *) self.myViewController;
        [vc protocolMethod];
}

The UIViewController <MyProtocol> * type-cast translates to "vc is a UIViewController object that conforms to MyProtocol", whereas using id <MyProtocol> translates to "vc is an object of an unknown class that conforms to MyProtocol".

This way the compiler will give you proper type checking on vc - the compiler will only give you a warning if any method that's not declared on either UIViewController or <MyProtocol> is called. id should only be used in the situation if you don't know the class/type of the object being cast.

Solution 2

You can cast it like this:

if([self.myViewController conformsToProtocol:@protocol(MyProtocol)])
{
    id<MyProtocol> p = (id<MyProtocol>)self.myViewController;
    [p protocolMethod];
}

This threw me for a bit, too. In Objective-C, the protocol isn't the type itself, so you need to specify id (or some other type, such as NSObject) along with the protocol that you want.

Share:
36,616

Related videos on Youtube

Ford
Author by

Ford

SQL, Cocoa, Medicine

Updated on July 08, 2022

Comments

  • Ford
    Ford almost 2 years

    I have an object (a UIViewController) which may or may not conform to a protocol I've defined.

    I know I can determine if the object conforms to the protocol, then safely call the method:

    if([self.myViewController conformsToProtocol:@protocol(MyProtocol)]) {
        [self.myViewController protocolMethod]; // <-- warning here
    }
    

    However, XCode shows a warning:

    warning 'UIViewController' may not respond to '-protocolMethod'
    

    What's the right way to prevent this warning? I can't seem to cast self.myViewController as a MyProtocol class.

  • Ford
    Ford over 15 years
    Ah, cool, thanks. I just checked and saw that casting it as (id) works too. Is that bad form?
  • TOMKA
    TOMKA over 15 years
    If you cast it as id<MyProtocol> then the compiler will warn you if you use methods that aren't defined in that protocol.
  • Andy
    Andy over 15 years
    @dreamlax - This is how the compiler does type checking against protocols. See developer.apple.com/documentation/Cocoa/Conceptual/Objective‌​C/… for more info.
  • Andy
    Andy over 15 years
    @Ford - it would be better to use the the protocol specifically, since that way the compiler can perform some type checking for you.
  • Ford
    Ford over 15 years
    @Andy, I don't think you need the '*' since 'id' is already a pointer. So: id<MyProtocol> p = (id<MyProtocol>)self.myViewController; [p protocolMethod]; Or just: [(id<MyProtocol>)self.myViewController protocolMethod];
  • memmons
    memmons over 10 years
    When using protocols you really shouldn't care about the object type -- the whole point of a protocol is that any object type can adopt it and be used without having to cast to the specific object. So, I would recommend using the answer by @andy anywhere you are casting to a protocol instead of the above -- id<MyProtocol> p = (id<MyProtocol>)self.myViewController; This answer and @andys are both correct, but his is more correct.
  • Nick Forge
    Nick Forge over 10 years
    @Answerbot your comment is incorrect, and misses the point I made in the last paragraph of my answer. You might or might not care about the object type, it depends on the situation. What happens if you want to send a message declared on UIViewController to vc in the example in my answer, and it's declared as id <MyProtocol>?
  • memmons
    memmons over 10 years
    Not sure what in regards to my comment is incorrect? In any case, if you are checking if an object conforms to a protocol why would you then call some other method unrelated to the protocol? I can't recall ever needing to do this or seeing this in code I've reviewed. Seems like a code smell to me.
  • Nick Forge
    Nick Forge over 10 years
    Just because you haven't seen/used it, doesn't mean it's a code smell. Here's a code snippet showing one example of where throwing away type information by using id is a problem: gist.github.com/nsforge/7743616
  • nambatee
    nambatee over 6 years
    anyone knows why this puts in me in an infinite loop when called on a subclass of UICollectionView with if([self conformsToProtocol:@protocol(MyProtocol)])?