2010-11-24 24 views
13

Antes de iOS 4, solía agregar un observador a cada MKAnnotationView agregado a la vista de mapa, escuchando su método seleccionado, así sé cuándo el usuario ha tocado un alfiler.¿Cómo probar un protocolo para un método?

Esto funcionó bien hasta iOS 4.2. Me di cuenta en el lanzamiento que las vistas de anotación notadas están siendo reutilizadas y de alguna manera se equivoca con los observadores.

Me imagino que puedo usar el método -mapview:didSelectAnnotationView: de MKMapViewDelegate para mis necesidades, pero eso solo se ha agregado al iOS 4.0 SDK.

Entonces, para mantener la compatibilidad, me gustaría implementar este método en mi delegado y verificar condicionalmente la presencia de este método en el protocolo MKMapViewDelegate para que, si no está presente, agregue mi observador a la vista de anotación .

¿Cómo puedo hacer esto para un método de protocolo, del mismo modo para la forma en que verificamos si una clase no es nula?

ACTUALIZACIÓN:

Como Daniel Dickison señaló, no puedo usar respondsToSelector:, porque mi delegado ha implementado para -mapview:didSelectAnnotationView: 4.0+ dispositivos. Lo que necesito es verificar si el protocolo en ese dispositivo tiene el método -mapview:didSelectAnnotationView: opcional O si MKMapView buscará ese método en su delegado.

Terminé haciendo una prueba para la versión actual de iOS en ejecución. Si es superior a 4.0, MKMapView buscará ese método y lo llamará.

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

Esto resuelve el problema original, pero aún sería interesante comprobar el protocolo real para el método de alguna manera.

Respuesta

5

Eso es un asunto difícil. Entonces, si estoy entendiendo su pregunta correctamente, quiere saber, en tiempo de ejecución, si la vista de mapa envía el mensaje mapView:didSelectAnnotationView: a su delegado. Pero no puede usar conformsToProtocol: o respondsToSelector: porque está implementando el delegado, por lo que obviamente está adoptando el protocolo e implementando el método.

Lo único que se me ocurre es buscar algún otro método que se haya agregado al MKMapView (no al delegado) en iOS 4, como: mapRectThatFits:.

Otra posibilidad es utilizar el Objective-C runtime library para consultar el objeto Protocol.Pero esto probablemente sea excesivo, y tampoco creo que funcione porque Protocol object is created by the compiler cuando construyes tu aplicación, y es posible que obtengas el objeto de protocolo MKMapViewDelegate definido por el SDK de UIKit en lugar de con el que se compiló el tiempo de ejecución.

2

me gustaría utilizar el método respondsToSelector: debido a que le permite comprobar si hay métodos específicos (que suena como que está haciendo, de lo contrario, si usted' Estoy buscando verificar un protocolo específico, la respuesta de @ Eric es buena). Este SO post habla sobre usarlo de esta manera.

Básicamente, la manera en que se utiliza es

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

Chris - puede que no desee utilizar la palabra clave reservada seleccionar como el nombre de la variable SEL. – DHamrick

+0

@DHamrick, tienes toda la razón ... tan tonto ... Lo escribí rápidamente y tenía una palma de la cara ... –

+1

¡No puedes usar "respondsToSelector" porque el único objeto que le pedirías es a ti mismo! Necesita averiguar si MKMapView buscará ese método de un delegado ... –

0

He adoptado un enfoque ligeramente diferente.

Simplemente uso un #ifdef (__iPHONE_OS_VERSION_MIN_REQUIRED... y agrego el observador si es necesario, junto con el método de delegado -mapview:didSelectAnnotationView:.

+0

"#ifdef (__iPHONE_OS_VERSION_MIN_REQUIRED" se resolverá en tiempo de compilación, no en tiempo de ejecución, por lo que una vez que compile su aplicación, siempre hará lo mismo sin importar en qué dispositivo/sistema operativo se está ejecutando. –

+0

Sí. Así fue cómo resolví el problema que describió. – joshpaul

+0

Esto no funciona. Necesita conocer la versión iOS del dispositivo en tiempo de ejecución, no en tiempo de compilación. '__iPHONE_OS_VERSION_MIN_REQUIRED' siempre devolverá el valor especificado en la configuración de compilación, sin importar qué dispositivo/iOS versión en la que lo está ejecutando. – leolobato

26

Como no hay una instancia de objeto, puede preguntar si responde a un selector de mensajes, y usted ya sabe que el protocolo es compatible pero solo está buscando un método: necesita usar protocol_getMethodDescription, así (el método es instancia de clase y opcional) donde se comprueba si hay un valor de retorno nulo:

#import <objc/runtime.h> 

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

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

¿No debería el protocolo ser referenciado como '@protocol (MKMapViewDelegate)'? En cualquier caso, tengo la sensación de que va a utilizar el MKMapViewDelegate proporcionado por el SDK en lugar del tiempo de ejecución. –

+0

Tiene razón acerca de @protocol (he corregido el código) pero dado que la verificación es en tiempo de ejecución, se verá el protocolo que existe en el momento en que se ejecuta la aplicación. Probablemente también, el marco MKMapKit debe estar débilmente vinculado (en el objetivo de la aplicación, haga "Obtener información", luego, en la pestaña General, mire hacia abajo en la lista de marcos y cambie MapKit de "requerido" a "débil"). –

+0

Consulte los dos últimos párrafos de la sección "Objetos del protocolo" en este documento: creo que implica que * puede * obtener el protocolo definido por el SDK en lugar del tiempo de ejecución. http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProtocols.html#//apple_ref/doc/uid/TP30001163-CH15-TPXREF149 –

Cuestiones relacionadas