2010-03-18 5 views
7

¿Hay alguna forma de proporcionar una implementación de método (que lleva exactamente el mismo nombre de un método definido por el marco) solo cuando el método no está ya definido en el sistema? Por ejemplo, el método [NSSomeClass someMethod:] existe solo en Mac OS X 10.6 y si mi aplicación se ejecuta en 10.5, proporcionaré la definición de ese método en una categoría. Pero cuando la aplicación se ejecuta en 10.6, quiero que se ejecute el método proporcionado por el sistema operativo.Anulando condicionalmente un método de sistema por categorías en Objective-C?

Fondo: Estoy creando una aplicación dirigida tanto para 10.5 como para 10.6. El problema es que recientemente me di cuenta de que el método +[NSSortDescriptor sortDescriptorWithKey:ascending:] solo existe en 10.6 y mi código ya está cubierto por esa llamada al método. Podría proporcionarle una implementación predeterminada (ya que esta vez no es demasiado difícil implementarlo yo mismo), pero quiero que se llame al "nativo" siempre que mi aplicación se ejecute en 10.6. Además, si encuentro problemas similares en el futuro (con métodos más difíciles de implementar), es posible que no pueda salirse con la suya proporcionando un reemplazo de una sola línea.

Esta pregunta vagamente similar a Override a method via ObjC Category and call the default implementation? pero la diferencia es que quiero proporcionar implementaciones solo cuando el sistema no tiene una.

Gracias.

Respuesta

4

Sí, esto es posible. Dado que apuntas 10.5+, estoy asumiendo que estás usando el tiempo de ejecución ObjC2, lo que lo hace bastante sencillo.

El Objective-C Runtime Reference tiene todos los métodos que necesitará. Específicamente, puede usar class_getClassMethod o class_getInstanceMethod para ver si el método ya existe, y luego class_addMethod para vincular su implementación a ese selector si la clase aún no lo tiene.

1

Como alternativa, puede hacer un buscar y sub -[NSSortDescriptor initWithKey:ascending:] y luego agregar la declaración de lanzamiento correspondiente.

Es más complicado de implementar pero mucho menos frágil y propenso a errores que la alteración de la clase. Eso es especialmente cierto si nunca has hecho eso antes. Probablemente pasará más tiempo acelerando la anulación de lo que haría con el hallazgo.

7

Compilaría +[NSSortDescriptor sortDescriptorWithKey:ascending:] en una categoría en un paquete separado. Luego, al principio de su main, verifique si la clase NSSortDescriptor tiene el método sortDescriptorWithKey:ascending: con respondsToSelector:. Si no está implementado (es decir, si se está ejecutando en < 10.6), luego cargue el paquete con -[NSBundle loadAndReturnError:].

De esta forma, ejecutará el método proporcionado por el sistema operativo en 10.6 y su implementación en 10.5.

+4

+1 enfoque inteligente :) –

+0

De acuerdo. Muy bueno de verdad. –

0

pensar en el compromiso entre cambiar initWithKey: ascendente: método y y agregar un nuevo método en tiempo de ejecución - solo subclase NSSortDescriptor y reemplazar todas las llamadas NSSortDescriptor con NSMySortDescriptor;

//NSMySortDescriptor.h 
@interface NSMySortDescriptor : NSSortDescriptor { 
} 
- (id)initWithKey:(NSString *)keyPath ascending:(BOOL)ascending 
@end 

//NSMySortDescriptor.m 

@implementation NSMySortDescriptor 
- (id)initWithKey:(NSString *)keyPath ascending:(BOOL)ascending{ 
    // check if super i.e. has initWithKey:ascending: method 
    if([NSSortDescriptor instancesRespondToSelector:@selector(initWithKey:ascending:)]) { 
     [NSSortDescriptor initWithKey:ascending:]; 
    } 
    else{ 
    // your custom realization for Mac OS X 10.5 
    //... 
    } 
} 
@end 
+1

'NSSortDescriptor' nunca responderá a' + initWithKey: ascendente: ', porque (por convención) no se supone que los métodos de clase usen' init' en sus nombres. –

+0

Oh sí, mi error: lo he tomado del código de pregunta original. Ciertamente [[clase NSSortDescriptor] respondsToSelector: @selector (sortDescriptorWithKey: ascendente :)]; o Oh sí, mi error, tómalo del código de pregunta original.Ciertamente, [NSSortDescriptor instancesRespondToSelector: @selector (initWithKey: ascendente :)]; - gracias; – Vladimir

Cuestiones relacionadas