Как проверить протокол для метода? - PullRequest
13 голосов
/ 24 ноября 2010

До iOS 4 я обычно добавлял наблюдателя к каждому MKAnnotationView, добавленному в представление карты, прислушиваясь к выбранному методу, поэтому я знаю, когда пользователь нажал на булавку.

Это сработалохорошо до iOS 4.2.Я заметил, что в выпуске отмеченные представления аннотаций фактически используются повторно, и это каким-то образом портит наблюдателей.

Так что я полагаю, что для своих нужд я могу использовать метод -mapview:didSelectAnnotationView: из MKMapViewDelegate, но этобыл добавлен только в iOS 4.0 SDK.

Итак, для обеспечения совместимости я хотел бы реализовать этот метод в моем делегате и условно проверить наличие этого метода в протоколе MKMapViewDelegate, чтобы, еслиего нет, я добавлю своего наблюдателя в представление аннотаций.

Как я могу сделать это для метода протокола, аналогично тому, как мы проверяем, не является ли класс нулевым?

ОБНОВЛЕНИЕ :

Как отметил Дэниел Дикисон, я не могу использовать respondsToSelector:, потому что у моего делегата реализовано -mapview:didSelectAnnotationView: для устройств 4.0+.Мне нужно проверить, есть ли в протоколе на этом устройстве необязательный метод -mapview:didSelectAnnotationView: ИЛИ , если MKMapView будет искать этот метод в своем делегате.

В итоге я сделалтест для текущей версии iOS работает.Если оно выше 4.0, MKMapView будет искать этот метод и вызывать его.

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

Это решает исходную проблему, но все равно было бы интересно как-то проверить фактический протокол для метода.

Ответы [ 5 ]

26 голосов
/ 25 ноября 2010

Поскольку нет экземпляра объекта, вы можете спросить, отвечает ли он на селектор сообщений, и вы уже знаете, что протокол поддерживается, но вы просто ищете один метод внутри - вам нужно использовать protocol_getMethodDescription, например, так (методявляется экземпляром класса и является необязательным), где вы проверяете нулевое возвращаемое значение:

#import <objc/runtime.h>

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

if ( hasMethod.name != NULL )
{
...
}
5 голосов
/ 25 ноября 2010

Это сложно. Поэтому, если я правильно понимаю ваш вопрос, вы хотите во время выполнения выяснить, отправляет ли представление карты сообщение mapView:didSelectAnnotationView: своему делегату. Но вы не можете использовать conformsToProtocol: или respondsToSelector:, потому что вы реализуете делегат, поэтому очевидно, что вы принимаете протокол и реализуете метод.

Единственное, о чем я могу думать, это проверить какой-то другой метод, который был добавлен в MKMapView (не делегат) в iOS 4, например: mapRectThatFits:.

Другой возможностью является использование библиотеки времени выполнения Objective C для запроса объекта протокола. Но это, вероятно, излишне, и я также не думаю, что это будет работать, потому что объект протокола создается компилятором при сборке приложения, и возможно, вы получите UIKit SDK-определяемый MKMapViewDelegate объект протокола вместо того, с чем была скомпилирована среда выполнения.

3 голосов
/ 25 ноября 2010

Я думаю, что вы хотите NSObject conformsToProtocol - что-то вроде:

BOOL test = [myObject conformsToProtocol:@protocol(MKMapViewDelegate)];
2 голосов
/ 25 ноября 2010

Я бы использовал метод respondsToSelector:, потому что он позволяет вам проверять определенные методы (что звучит так, как будто вы делаете, в противном случае, если вы хотите проверить определенный протокол, ответ @ Eric хороший один). Это ТАК сообщение говорит об использовании его таким образом.

По сути, вы бы использовали

SEL methodName = @selector(mymethod:);
BOOL test = [object respondsToSelector:methodName];
0 голосов
/ 25 ноября 2010

Я выбрал немного другой подход.

Я просто использую #ifdef (__iPHONE_OS_VERSION_MIN_REQUIRED... и добавляю наблюдателя, если необходимо, наряду с использованием метода делегата -mapview:didSelectAnnotationView:.

...