如何测试方法的协议?

时间:2010-11-24 20:53:28

标签: iphone objective-c cocoa cocoa-touch mapkit

在iOS 4之前,我曾经为添加到地图视图的每个MKAnnotationView添加了一个观察者,听取了它的选择方法,所以我知道用户何时点击了一个图钉。

这适用于iOS 4.2。我注意到在发布时注意到注释视图实际上正在被重用,并且它在某种程度上与观察者混淆。

所以我认为我可以使用-mapview:didSelectAnnotationView:中的MKMapViewDelegate方法来满足我的需求,但这只是添加到iOS 4.0 SDK中。

因此,为了保持兼容性,我想在我的委托上实现此方法,并有条件地检查MKMapViewDelegate协议上是否存在此方法,以便如果它不存在,我将添加我的观察者注释视图。

我如何为协议方法执行此操作,类似于我们如何检查类是否为零?

更新

Daniel Dickison指出,我不能使用respondsToSelector:,因为我的代表已为4.0+设备实施了-mapview:didSelectAnnotationView:。我需要检查该设备上的协议是否具有可选的-mapview:didSelectAnnotationView:方法 OR ,如果MKMapView将在其代理上查找该方法。

我最终对当前运行的iOS版本进行了测试。如果它高于4.0,MKMapView将查找该方法并调用它。

if ([[[UIDevice currentDevice] systemVersion] doubleValue] < 4.0)
    [self setupObserver];

这解决了原始问题,但以某种方式检查方法的实际协议仍然很有趣。

5 个答案:

答案 0 :(得分:26)

因为没有对象实例,您可以询问它是否响应消息选择器,并且您已经知道协议是受支持的,但您只是在寻找一种方法 - 您需要使用protocol_getMethodDescription,如此(方法是类实例和可选),您检查nil返回值:

#import <objc/runtime.h>

struct objc_method_description hasMethod = protocol_getMethodDescription(@protocol(MKMapViewDelegate), @selector(mapView:didSelectAnnotationView:), NO, YES);

if ( hasMethod.name != NULL )
{
...
}

答案 1 :(得分:5)

这是一个棘手的问题。因此,如果我正确理解您的问题,您希望在运行时找出地图视图是否将mapView:didSelectAnnotationView:消息发送给其委托。但是,您无法使用conformsToProtocol:respondsToSelector:因为您正在实施代理,所以很明显您正在采用该协议并实施该方法。

我唯一能想到的是检查在iOS 4中添加到MKMapView(而不是委托)的其他方法,例如:mapRectThatFits:

另一种可能性是使用Objective-C runtime library来查询Protocol对象。但这可能有些过分,而且我认为它不会起作用,因为Protocol object is created by the compiler在您构建应用时,您可能会获得UIKit SDK定义的{{0}} {1}}协议对象,而不是编译运行时的任何内容。

答案 2 :(得分:3)

我认为你想要NSObject conformsToProtocol - 类似于:

BOOL test = [myObject conformsToProtocol:@protocol(MKMapViewDelegate)];

答案 3 :(得分:2)

我会使用respondsToSelector:方法因为这可以让你检查特定的方法(这听起来像你正在做的,否则,如果你想检查一个特定的协议,@ Eric的答案是一个好的)。这篇SO post讨论了如何以这种方式使用它。

基本上,你使用它的方式是

SEL methodName = @selector(mymethod:);
BOOL test = [object respondsToSelector:methodName];

答案 4 :(得分:0)

我采取了略微不同的方法。

我只需使用#ifdef (__iPHONE_OS_VERSION_MIN_REQUIRED...并在必要时添加观察者,并使用-mapview:didSelectAnnotationView:委托方法。