2012-07-13 13 views
6

Escribo una subclase de UITableView y quiero que mi subclase maneje algunos de los métodos de UITableViewDelegate antes de pasarlos junto con el delegado "real", así como reenviar todos los métodos de UITableViewDelegate no implementados por mi subclase.Shared UITableViewDelegate

En la subclase I tienen una propiedad privada:

que mantiene el "delegado real" que todos los métodos no implementados deben enviar al. En mis dos métodos init puse

self.delegate = self; 

y puedo reemplazar - (void) setDelegate: (id) como esto

-(void)setDelegate:(id<UITableViewDelegate>)delegate { 
    if (delegate != self) { 
     _trueDelegate = delegate; 
    } else { 
     [super setDelegate:self]; 
    } 
} 

Entonces anular estos para manejar el reenvío de mensajes

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { 
    NSMethodSignature *sig; 
    sig = [[self.delegate class] instanceMethodSignatureForSelector:aSelector]; 
    if (sig == nil) { 
     sig = [NSMethodSignature signatureWithObjCTypes:"@^v^c"]; 
    } 
    return sig; 
} 

- (void)forwardInvocation:(NSInvocation *)anInvocation { 
    SEL selector = anInvocation.selector; 
    if ([self respondsToSelector:selector]) { 
     [anInvocation invokeWithTarget:self]; 
    } else { 
     [anInvocation invokeWithTarget:_trueDelegate]; 
    } 
} 

El problema es que los métodos delegados no implementados nunca se invocan en la tabla vista, por lo tanto, no se les da la oportunidad de ser reenviados al objeto _trueDelegate.

Me trataron de comprobar por ellos aquí:

- (BOOL)respondsToSelector:(SEL)aSelector { 

} 

pero ese método no se llama a los métodos UITableViewDelegate aunque las capturas de otros métodos bien.

+0

¿Ha declarado su clase extendida como conforme a los protocolos de delegado? –

+0

Pregunto porque es posible que tableView use 'conformsToProtocol:' en lugar de 'respondsToSelector:' al llamar a métodos delegados. –

+0

De hecho lo hice, ese podría ser el problema, lo comprobaré – Lance

Respuesta

12

Para el rendimiento, UITableView comprueba y recuerda qué métodos de delegado están disponibles tan pronto como se establece el delegado. Primero configura el delegado self, luego el trueDelegate. Entonces en el momento en que el delegado se configura en el UITableView, trueDelegate es nil, y entonces -respondsToSelector: en ese siempre devuelve NO.

Para solucionar eso, configure el delegado después de configurar trueDelegate. Además, puede simplificar el código de reenvío. Elimine todo el código que tiene arriba excepto la propiedad y reemplácela por:

- (void)setDelegate:(id <UITableViewDelegate>)delegate 
{ 
    if (delegate == self) return; 

    self.trueDelegate = delegate; 
    [super setDelegate:self]; 
} 

- (BOOL)respondsToSelector:(SEL)aSelector 
{ 
    if ([super respondsToSelector:aSelector]) return YES; 

    return [self.trueDelegate respondsToSelector:aSelector]; 
} 

- (id)forwardingTargetForSelector:(SEL)aSelector 
{ 
    return self.trueDelegate; 
} 
+0

¡Gracias! Esto es perfecto, solo curiosidad. ¿Cómo se enteró de la optimización UITableView mencionada? – Lance

+0

Me tropecé con esto hace algún tiempo cuando se trataba de implementar delegados de la manera correcta. Los '_tableFlags' en' UITableView.h' dan una muy buena sugerencia de que 'UITableView' almacena en caché qué métodos se implementan en su delegado/fuente de datos. –

+1

Respuesta impresionante, intenté todo hasta que obtuve su pista. –

Cuestiones relacionadas