Pregunta

Me gustaría anular un método en una clase de Objective C que no tengo la fuente.

Lo he investigado y parece que las Categorías deberían permitirme hacer esto, pero me gustaría usar el resultado del método antiguo en mi nuevo método, usando super para obtener el resultado de los métodos antiguos.

Sin embargo, siempre que intento esto, se llama a mi método, pero " super " es nil ... ¿Alguna idea de por qué? Estoy haciendo el desarrollo de iPhone con XCode 2.2 SDK. Definitivamente estoy trabajando con una instancia de una clase, y el método de la clase es un método de instancia.

@implementation SampleClass (filePathResolver)
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
    NSString *result = [super fullPathFromRelativePath: relPath];

  ... do some stuff with the old result

    return result;
}

Nota y aclaración: por lo que puedo ver en los Apple Docs, me parece que esto debería estar permitido.

  

Documentos de categorías en developer.apple.com:   Cuando una categoría anula un método heredado, el método en el   La categoría puede, como es habitual, invocar el   implementación heredada a través de un mensaje   Super. Sin embargo, si una categoría   anula un método que ya   existía en la categoría de la categoría, allí   No hay manera de invocar el original.   implementación.

¿Fue útil?

Solución

Las categorías extienden la clase original, pero no las subclasifican, por lo tanto, una llamada a super no encuentra el método.

Lo que quieres se llama Método Swizzling . Pero ten en cuenta que tu código podría romper algo. Hay un artículo en Theocacao escrito por Scot Stevenson sobre el Método Swizzling en el antiguo Runtime de Objective-C, Cocoa with Love por Matt Gallagher tiene un artículo sobre el método Swizzling en el nuevo objetivo -C 2.0 tiempo de ejecución y un simple reemplazo para él.

Como alternativa, puede crear una subclase de la clase y luego usar la subclase o usar + (void) poseAsClass: (Class) aClass para reemplazar la superclase . Apple escribe:

  

Un método definido por una clase posando   Puede, a través de un mensaje a super ,   Incorporar el método superclase.   anulaciones.

Tenga en cuenta que Apple ha desaprobado poseAsClass: en Mac OS X 10.5.

Otros consejos

Si va a codificar contra esta clase, simplemente cambie el nombre del selector a algo que su código pueda usar, y llame al selector original en self :

@implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
    NSString *result = [self fullPathFromRelativePath: relPath];

  ... do some stuff with the old result

    return result;
}

Si desea anular la implementación predeterminada de este selector para esa clase, deberá usar método swizzling enfoque.

No exactamente en la categoría pero hay una solución al agregar el método dinámicamente en tiempo de ejecución. Samuel Défago en su artículo describe una forma clara de crear una implementación IMP de bloque llamando a super, su artículo original se puede encontrar aquí

El código relevante es:

#import <objc/runtime.h>
#import <objc/message.h>

    const char *types = method_getTypeEncoding(class_getInstanceMethod(clazz, selector));
    class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
        struct objc_super super = {
            .receiver = self,
            .super_class = class_getSuperclass(clazz)
        };

        id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper;
        return objc_msgSendSuper_typed(&super, selector, argp);
    }), types);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top