如何测试方法的协议?

leo*_*ato 13 iphone cocoa cocoa-touch objective-c mapkit

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

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

所以我想我可以-mapview:didSelectAnnotationView:根据MKMapViewDelegate我的需要使用该方法,但这只是添加到iOS 4.0 SDK中.

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

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

更新:

正如Daniel Dickison指出的那样,我无法使用respondsToSelector:,因为我的代表已经-mapview:didSelectAnnotationView:实现了4.0+设备.我需要的是检查该设备上的协议是否具有可选-mapview:didSelectAnnotationView:方法是否MKMapView将在其委托上查找该方法.

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

if ([[[UIDevice currentDevice] systemVersion] doubleValue] < 4.0)
    [self setupObserver];
Run Code Online (Sandbox Code Playgroud)

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

Ken*_*ner 26

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

#import <objc/runtime.h>

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

if ( hasMethod.name != NULL )
{
...
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*son 5

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

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

另一种可能性是使用Objective-C运行时库来查询Protocol对象.但这可能有点过头了,而且我认为它不会起作用,因为Protocol对象是由编译器在构建应用程序时创建的,而且你可能会得到UIKit SDK定义的MKMapViewDelegate协议对象而不是运行时编译了.