2012-01-25 19 views
15

Mam UIScrollView, który muszę podklasy i wewnątrz podklasy muszę dołączyć UIScrollViewDelegate, dzięki czemu mogę wdrożyć metodę viewForZoomingInScrollView.Kilku delegatów na jeden obiekt?

Wtedy mam UIViewController gdzie potrzebne do utworzenia wystąpienia obiektu tego UIScrollView podklasy, który został utworzony, i chciałbym również, aby UIViewController UIScrollViewDelegate dla tego obiektu, więc mogę realizować scrollViewDidZoom w tym UIViewController klasie.

Jak można uczynić jeden obiekt dwoma delegatami? (Wiem, że mogłem po prostu mieć jednego delegata i po prostu wdrożyć obie metody tam, ale dla celów projektowych chciałbym to zrobić tak, jak wspomnę).

+0

Dlaczego miałbyś to zrobić? Dlaczego nie możesz po prostu przekazać wiadomości z customScrollView do swojego VC, który ma SV (z drugim (niestandardowym) delegatem)? –

+0

Może to jest właśnie to, co muszę zrobić, więc jeśli zaimplementowałem scrollViewDidZoom w mojej podklasie SV, w jaki sposób mogę wysłać wiadomość VC, gdy zostanie ona uruchomiona? @totumus maximus –

+0

Będziesz musiał utworzyć niestandardowego delegata (protokół) w widoku niestandardowym i uczynić go swoim delegatem VC. W chwili, gdy delegaci przewijania zostaną wezwani, należy również wywołać jedną z niestandardowych metod delegowania w niestandardowym uczestniku. W ten sposób widok przewijania zachowuje swoją odpowiedzialność, a widok rodzica reaguje na konkretną funkcję przewijania. Powiem to w odpowiedzi dla ciebie. –

Odpowiedz

7

Nie chcesz obiektu z 2 uczestnikami. Chcesz, aby Twój customScrollView zachowywał odpowiedzialność za własne funkcje UIScrollViewDelegate.

Aby umożliwić rodzicowi VC odpowiedź na metody delegatów UIScrollView, należy wprowadzić niestandardowego delegata w swoim customScrollView.

W tej chwili wywoływana jest funkcja UIScrollViewDelegate, a także wywoływana jest jedna z funkcji delegata od niestandardowego uczestnika. W ten sposób twój parentVC zareaguje w momencie, gdy tego chcesz.

Będzie to wyglądać mniej więcej tak.

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 
} 

Mam nadzieję, że w pełni pokrywa problemu. Powodzenia.

+0

Dzięki za napisanie tego. –

+0

Zawsze chętnie pomożemy ^^ –

+2

@TotumusMaximus a ScrollView ma już właściwość o nazwie "delegate", tutaj próbujesz zadeklarować właściwość o tej samej nazwie, która jest ZŁA – onmyway133

2

Nie sądzę, że można mieć dwóch delegatów bezpośrednio połączonych z tym samym obiektem.

To, co możesz zrobić, to połączenie dwóch delegatów z siecią. Oznacza to, że łączysz jednego delegata z drugim, a następnie przekazujesz poprzednie wiadomości do przodu, gdy nie może on obsługiwać ich bezpośrednio.

W każdym razie, wydaje mi się, że brakuje mi trochę, aby w pełni zaproponować rozwiązanie, a mianowicie powód, dla którego potrzebujesz drugiego delegata i nie zawsze można to zrobić za pośrednictwem jednego delegata. Innymi słowy, uważam, że mogą istnieć alternatywne projekty, które pozwoliłyby uniknąć dwóch delegatów.

3

Krótka odpowiedź: nie. Delegaci są zazwyczaj słabe relacja jeden-do-jednego:

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

Czasami można zobaczyć „słuchacza” wzorca projektowego, który jest formą jeden-do-wielu delegatów:

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

W Twój przypadek, nie wydaje się być dobrym publicznym punktem korekcji w UIScrollView, który pozwala podklasom na określenie viewForZoomingInScrollView. Unikałbym uczynienia UIScrollView swoim własnym delegatem, jeśli to możliwe. Możesz uczynić UIViewController UIScrollViewDelegate i zapewnić mu viewForZooming. Lub możesz utworzyć podklasę widoków pośrednich, która używa UIScrollView, zapewnia viewForZooming i przekazuje inne metody delegatów.

12

Czasami warto dołączyć kilku delegatów do widoku przewijania. W tym przypadku można zbudować prosty rozgałęźnik delegacji:

// 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 

Następnie wystarczy ustawić instancję tego rozdzielacza jako delegat widoku przewijania i dołączyć dowolną liczbę delegatów do rozdzielacza. Wszyscy oni otrzymają wydarzenia delegacji. Obowiązują pewne zastrzeżenia, na przykład zakłada się, że wszyscy delegaci są tego samego typu, w przeciwnym razie będziesz mieć kłopot z naiwną implementacją respondsToSelector. To nie jest duży problem, łatwo jest zmienić implementację, aby wysyłała tylko zdarzenia delegowania do tych, którzy ich wspierają.

+0

powinna być zadeklarowana jako @property (przypisać) CCDelegateSplitter * delegaci? –

+2

zamiast zestawu [NSMutableSet]; użyj [NSHashTable hashTableWithOptions: NSPointerFunctionsWeakMemory]; ponieważ będzie zawierał słabe odniesienie do obiektów delegowanych i uniknie dla nich cyklu zatrzymania. – Nav

+0

Nie używaj tego rozwiązania, delegatów nie można zwolnić z powodu odwołania. Użyj tego, co sugeruje Nav, NSNotification lub czegoś innego. Po prostu nie to ... –

0

Oto eleganckie rozwiązanie z udziałem 2 delegatów:

  • niestandardowej klasy widoku przewijania LTInfiniteScrollView podklasy UIView (nie UIScrollView) i dodaje UIScrollView jako dziecko. LTInfiniteScrollView ustawia się jako delegat tego UIScrollView.

  • LTInfiniteScrollView definiuje własną właściwość delegate i protokół. Ponieważ LTInfiniteScrollView nie ma podklasy UIScrollView, nie istnieje żadna istniejąca właściwość, z którą mógłby się konfliktować.

Powiązane problemy