Как протестировать протокол для метода?
Перед iOS 4 я использовал добавление наблюдателя к каждому MKAnnotationView
, добавленному в представление карты, прислушиваясь к выбранному ему методу, поэтому я знаю, когда пользователь нажал на контакт.
Это отлично работало с iOS 4.2. Я заметил, что в выпуске замеченные аннотации на самом деле повторно используются, и это как-то мешает наблюдателям.
Итак, я полагаю, что могу использовать метод -mapview:didSelectAnnotationView:
из MKMapViewDelegate
для моих нужд, но это было добавлено только в iOS 4.0 SDK.
Итак, чтобы поддерживать совместимость, я хотел бы реализовать этот метод у своего делегата и условно проверить наличие этого метода в протоколе MKMapViewDelegate
, чтобы, если он не присутствует, я добавлю своего наблюдателя в аннотацию вид.
Как это сделать для метода протокола, аналогично тому, как мы проверяем, не класс ли nil?
UPDATE
Как отметил Даниэль Дикисон, я не могу использовать respondsToSelector:
, потому что мой делегат имеет -mapview:didSelectAnnotationView:
для 4.0+ устройств. Мне нужно проверить, имеет ли протокол на этом устройстве опционный метод -mapview:didSelectAnnotationView:
ИЛИ, если MKMapView
будет искать этот метод для делегирования.
Я закончил тест для текущей версии iOS. Если он выше 4.0, MKMapView
будет искать этот метод и вызывать его.
if ([[[UIDevice currentDevice] systemVersion] doubleValue] < 4.0)
[self setupObserver];
Это решает исходную проблему, но все равно будет интересно проверить фактический протокол для метода как-то.
Ответы
Ответ 1
Это сложная штука. Поэтому, если я правильно понимаю ваш вопрос, вы хотите узнать во время выполнения, отображает ли представление карты сообщение mapView:didSelectAnnotationView:
его делегату. Но вы не можете использовать conformsToProtocol:
или respondsToSelector:
, потому что вы реализуете делегат, поэтому, очевидно, вы принимаете протокол и реализуете этот метод.
Единственное, о чем я могу думать, это проверить какой-либо другой метод, который был добавлен в MKMapView
(а не делегат) в iOS 4, например: mapRectThatFits:
.
Другая возможность заключается в использовании Objective-C библиотеки времени выполнения для запроса объекта протокола. Но это, вероятно, слишком много, и я не думаю, что это сработает, потому что Объект протокола создается компилятором при создании вашего приложения, и возможно, вы получите UIKit SDK-определенный объект протокола MKMapViewDelegate
вместо того, чтобы скомпилировалось время выполнения.
Ответ 2
Поскольку нет экземпляра объекта, вы можете спросить, отвечает ли он на селектор сообщений, и вы уже знаете, что протокол поддерживается, но вы просто ищете один метод внутри - вам нужно использовать protocol_getMethodDescription
, например (метод является экземпляром класса и необязательным), где вы проверяете нулевое возвращаемое значение:
#import <objc/runtime.h>
struct objc_method_description hasMethod = protocol_getMethodDescription(@protocol(MKMapViewDelegate), @selector(mapView:didSelectAnnotationView:), NO, YES);
if ( hasMethod.name != NULL )
{
...
}
Ответ 3
Я думаю, что вы хотите NSObject соответствуетToProtocol - что-то вроде:
BOOL test = [myObject conformsToProtocol:@protocol(MKMapViewDelegate)];
Ответ 4
Я бы использовал метод respondsToSelector:
, потому что это позволяет вам проверять определенные методы (что похоже на то, что вы делаете, в противном случае, если вы хотите проверить конкретный протокол, @Eric ответ хороший один). Этот SO post говорит об использовании этого способа.
В принципе, способ, которым вы его используете, -
SEL methodName = @selector(mymethod:);
BOOL test = [object respondsToSelector:methodName];
Ответ 5
Я сделал несколько иной подход.
Я просто использую #ifdef (__iPHONE_OS_VERSION_MIN_REQUIRED...
и при необходимости добавляю наблюдателя, а также используя метод делегата -mapview:didSelectAnnotationView:
.