2010-11-24 101 views
13

在iOS 4之前,我曾经为添加到地图视图中的每个MKAnnotationView添加了一个观察者,监听它的选定方法,因此我知道用户何时点击了某个图钉。如何测试方法的协议?

这工作正常到iOS 4.2。我注意到,在发布的注释视图实际上被重用,并以某种方式与观察者混淆。

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

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

我该如何做一个协议方法,类似于我们如何检查一个类是不是零?

UPDATE

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

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

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

这解决了原来的问题,但它仍然将是有趣的检查实际协议的方法,不知何故。

回答

5

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

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

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

2

我会用respondsToSelector:方法,因为它允许你检查的具体方法(这听起来像你正在做的,否则,如果你”重新寻找一个特定的协议,@埃里克的答案是一个很好的答案)。这个SO post谈到使用这种方式。

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

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

克里斯 - 你可能不想使用保留关键字选择SEL作为变量名称。 – DHamrick 2010-11-24 21:34:48

+0

@DHamrick,你是绝对正确的......很愚蠢......我很快就写下了它,并有一个脸掌... – 2010-11-24 23:02:47

+1

你不能使用“respondsToSelector”,因为你会问它的唯一对象是你自己!你需要知道MKMapView是否会从委托中寻找这种方法... – 2010-11-24 23:14:39

0

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

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

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) 
{ 
... 
}