objective-c category categories super

objective c - ¿Usando Super en una Categoría de Objetivo C?



objective-c category (3)

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

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.

Cuando intento esto, se llama a mi método, pero "super" es nulo ... ¿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?

Categorías docs en developer.apple.com: cuando una categoría invalida un método heredado, el método en la categoría puede, como de costumbre, invocar la implementación heredada a través de un mensaje a super. Sin embargo, si una categoría anula un método que ya existía en la clase de la categoría, no hay forma de invocar la implementación original.


Las categorías extienden la clase original, pero no la 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 sobre Theocacao escrito por Scot Stevenson sobre Method Swizzling en el antiguo tiempo de ejecución de Objective-C, Cocoa with Love por Matt Gallagher tiene un artículo sobre Method Swizzling en el nuevo tiempo de ejecución de Objective-C 2.0 y un simple reemplazo.

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 de superclase que reemplaza.

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


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 la implementación de IMP en bloque llamando a super, su artículo original se puede encontrar here

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);


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 el método de método swizzling .