2012-01-25 16 views
15

Tengo un UIScrollView que necesito para crear una subclase y dentro de la subclase necesito adjuntar el UIScrollViewDelegate para poder implementar el método viewForZoomingInScrollView.¿Múltiples delegados por un objeto?

entonces tengo una UIViewController donde necesito crear una instancia de un objeto de esta subclase UIScrollView que he creado, y también me gustaría hacer el UIViewController un UIScrollViewDelegate para este objeto para que pueda aplicar scrollViewDidZoom en esta clase UIViewController.

¿Cómo es posible hacer que un objeto tenga dos delegados? (Sé que podría simplemente tener un delegado y simplemente implementar ambos métodos allí, pero para fines de diseño me gustaría hacerlo de la manera que lo menciono).

+0

¿Por qué harías esto? ¿Por qué no puede simplemente pasar un mensaje de su CustomScrollView a su VC que tiene el SV (con un segundo delegado (personalizado))? –

+0

Quizás eso es lo que tengo que hacer, así que si implementé scrollViewDidZoom en mi subclase SV, ¿cómo podría enviar mi VC un mensaje cada vez que se activara? @totumus maximus –

+0

Deberá crear un delegado (protocolo) personalizado en su vista personalizada y hacer que su delegado de VC lo haga. En el momento en que se llama a los delegados de scrollview, también se llama a uno de los métodos de delegado personalizados en su delegado personalizado. De esta forma, la vista de desplazamiento mantiene la responsabilidad de sí misma y la vista de los padres reacciona a la función de desplazamiento en particular. Lo pondré en una respuesta para ti. –

Respuesta

7

No desea un objeto con 2 delegados. Desea mantener su CustomScrollView manteniendo la responsabilidad de sus propias funciones UIScrollViewDelegate.

Para hacer que su parentVC responda a los métodos de delegado de UIScrollView también tendrá que crear un delegado personalizado dentro de su CustomScrollView.

En el momento en que se llama a una función UIScrollViewDelegate, también llamará a una de las funciones de delegado de su delegado personalizado. De esta forma, su parentVC responderá en el momento que lo desee.

Se verá algo así.

CustomScrollView.h

@protocol CustomDelegate <NSObject> 

//custom delegate methods 
-(void)myCustomDelegateMethod; 

@end 

@interface CustomScrollView : UIScrollView <UIScrollViewDelegate> 
{ 
    id<CustomDelegate> delegate 
    //the rest of the stuff 

CustomScrollView.m

-(void) viewForZoomingInScrollView 
{ 
    [self.delegate myCustomDelegateMethod]; 
    //rest of viewForZoomingInScrollView code 

ParentVC.h

@interface CustomScrollView : UIViewController <CustomDelegate> 
{ 
    //stuff 

ParentVC.m

-(void)makeCustomScrollView 
{ 
    CustomScrollView *csv = [[CustomScrollView alloc] init]; 
    csv.delegate = self; 
    //other stuff 

} 

-(void)myCustomDelegateMethod 
{ 
    //respond to viewForZoomingInScrollView 
} 

espero que esto cubre totalmente su problema. Buena suerte.

+0

Gracias por escribir eso. –

+0

Siempre dispuesto a ayudar ^^ –

+2

@TotumusMaximus un ScrollView ya tiene una propiedad llamada "delegar", aquí intenta declarar una propiedad con el mismo nombre, que es MALO – onmyway133

2

No creo que pueda tener dos delegados UIScrollViewDelegate directamente conectados al mismo objeto.

Lo que puede hacer es tener los dos delegados conectados en cadena. Es decir, conecta un delegado al otro, y luego tiene los primeros mensajes reenviados a este último cuando no puede manejarlos directamente.

En cualquier caso, creo que me falta un poco para sugerir completamente una solución, es decir, la razón por la que necesita un segundo delegado y no puede hacerlo siempre a través de un único delegado. En otras palabras, lo que creo es que podría haber diseños alternativos que evitarían la necesidad de dos delegados.

3

Respuesta corta: no es así. Los delegados son típicamente una débil relación uno-a-uno:

@property (nonatomic, weak /*or assign*/) id<MyViewDelegate> delegate; 

A veces se verá un patrón de diseño "oyente", que es la forma de uno a muchos de los delegados:

- (void) addListener:(id<MyViewListener>)listener; 
- (void) removeListener:(id<MyViewListener>)listener; 

En En su caso, no parece haber un buen punto de anulación pública en UIScrollView que permita a las subclases especificar viewForZoomingInScrollView. Evitaría hacer que UIScrollView sea su propio delegado, si es posible. Puede hacer que UIViewController sea UIScrollViewDelegate y que proporcione viewForZooming. O puede crear una subclase de vista intermedia que use UIScrollView, proporcione viewForZooming y reenvíe los otros métodos delegados.

12

A veces tiene sentido adjuntar varios delegados a una vista de desplazamiento. En ese caso, se puede construir un sencillo divisor de la delegación:

// Public interface 
@interface CCDelegateSplitter : NSObject 

- (void) addDelegate: (id) delegate; 
- (void) addDelegates: (NSArray*) delegates; 

@end 

// Private interface 
@interface CCDelegateSplitter() 
@property(strong) NSMutableSet *delegates; 
@end 

@implementation CCDelegateSplitter 

- (id) init 
{ 
    self = [super init]; 
    _delegates = [NSMutableSet set]; 
    return self; 
} 

- (void) addDelegate: (id) delegate 
{ 
    [_delegates addObject:delegate]; 
} 

- (void) addDelegates: (NSArray*) delegates 
{ 
    [_delegates addObjectsFromArray:delegates]; 
} 

- (void) forwardInvocation: (NSInvocation*) invocation 
{ 
    for (id delegate in _delegates) { 
     [invocation invokeWithTarget:delegate]; 
    } 
} 

- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector 
{ 
    NSMethodSignature *our = [super methodSignatureForSelector:selector]; 
    NSMethodSignature *delegated = [(NSObject *)[_delegates anyObject] methodSignatureForSelector:selector]; 
    return our ? our : delegated; 
} 

- (BOOL) respondsToSelector: (SEL) selector 
{ 
    return [[_delegates anyObject] respondsToSelector:selector]; 
} 

@end 

A continuación, basta con establecer una instancia de este divisor como delegado de la vista de desplazamiento y adjuntar cualquier número de delegados al divisor. Todos ellos recibirán los eventos de la delegación. Se aplican algunas advertencias, por ejemplo, se supone que todos los delegados son del mismo tipo, de lo contrario, tendrá problemas con la implementación ingenua de respondsToSelector. Este no es un gran problema, es fácil cambiar la implementación para enviar solo eventos de delegación a aquellos que los apoyan.

+0

en caso de que se declare como @propiedad (asignar) CCDelegateSplitter * delegados? –

+2

en lugar de un [conjunto NSMutableSet]; use [NSHashTable hashTableWithOptions: NSPointerFunctionsWeakMemory]; ya que mantendrá una referencia débil a los objetos delegados y evitará el ciclo de retención para ellos – Nav

+0

No use esta solución, los delegados no pueden ser desasignados debido a la referencia. Use lo que Nav sugirió, NSNotificación u otra cosa. Solo que no esto ... –

0

Aquí es una solución elegante que implica: 2 delegados

  • personalizado clase de vista de desplazamiento LTInfiniteScrollView subclases UIView (no UIScrollView) y añade un UIScrollView como un niño. LTInfiniteScrollView se establece como el delegado de este UIScrollView.

  • LTInfiniteScrollView define su propia propiedad delegate y un protocolo. Porque LTInfiniteScrollView no subclase UIScrollView, no hay ninguna propiedad existente delegate en conflicto.