在Objective-C中将类的实例强制转换为@protocol


102

我有一个对象(UIViewController),该对象可能符合也可能不符合我定义的协议。

我知道我可以确定对象是否符合协议,然后安全地调用该方法:

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

但是,XCode显示警告:

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

预防此警告的正确方法是什么?我似乎无法施展self.myViewController作为一个MyProtocol类。

Answers:


171

正确的方法是:

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

UIViewController <MyProtocol> *型铸造转换为“VC是一个UIViewController对象符合MyProtocol”,而使用id <MyProtocol>转换为“VC是一个未知类符合MyProtocol的目的”。

这样,编译器将为您提供正确的类型检查vc-如果未在UIViewController或未声明任何方法的情况下,编译器将仅向您发出警告<MyProtocol>id仅在您不知道要转换的对象的类/类型的情况下才应使用。


2
使用协议时,您实际上不必关心对象类型-协议的全部要点是,任何对象类型都可以采用它并且无需强制转换为特定对象即可使用。因此,我建议您在要转换为协议的任何地方使用@andy的答案,而不是上面的方法- id<MyProtocol> p = (id<MyProtocol>)self.myViewController;这个答案和@andys都是正确的,但他的答案正确。
回忆录,

2
@Answerbot您的评论不正确,并且错过了我在答案的最后一段中提出的观点。您是否在乎对象类型,取决于情况。如果你想发送一条消息宣布会发生什么情况UIViewController,以vc在例如在我的答案,它的声明id <MyProtocol>
Nick Forge 2013年

不确定关于我的评论有误吗?无论如何,如果要检查对象是否符合协议,为什么还要调用与该协议无关的其他方法?我不记得曾经需要这样做或在我所审查的代码中看到过这个。在我看来就像是代码的气味。
回忆录,

仅仅因为您还没有看到/使用它,并不意味着它就是代码的味道。这是一个代码片段,显示了一个使用扔掉类型信息id的问题的示例
Nick Forge

60

您可以像这样进行投射:

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

这也让我感到有些惊讶。在Objective-C中,协议本身不是类型,因此您需要指定id(或其他类型,如NSObject)以及所需的协议。


啊,很酷,谢谢。我只是检查了一下,发现也可以将其转换为(id)工程。那是不好的形式吗?
福特

1
如果将其强制转换为id <MyProtocol>,则如果您使用该协议中未定义的方法,则编译器会警告您。
dreamlax

1
@dreamlax-这是编译器根据协议进行类型检查的方式。有关更多信息,请参见developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/…
安迪

1
@Ford-最好专门使用该协议,因为那样编译器可以为您执行某种类型检查。
安迪

1
@Andy,我认为您不需要'*',因为'id'已经是一个指针。因此:id <MyProtocol> p =(id <MyProtocol>)self.myViewController; [p protocolMethod]; 或者只是:[[id <MyProtocol>)self.myViewController protocolMethod];
福特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.