Несколько делегатов на один объект?


У меня есть UIScrollView, который мне нужен для подкласса, и внутри подкласса мне нужно прикрепить UIScrollViewDelegate, чтобы я мог реализовать метод viewForZoomingInScrollView.

Тогда у меня есть UIViewController, где мне нужно создать экземпляр объекта этого UIScrollView подкласса, который я создал, и я также хотел бы сделать UIViewController UIScrollViewDelegate для этого объекта, чтобы я мог реализовать scrollViewDidZoom в этом UIViewController классе.

Как можно сделать так, чтобы у одного объекта было два делегата? (Я знаю, что легко мог бы иметь только одного делегата и просто реализуйте оба метода там, но для целей дизайна я хотел бы сделать это так, как я упоминаю).

3 15

3 ответа:

Вам не нужен объект с 2 делегатами. Вы хотите, чтобы ваш customScrollView сохранял ответственность за свои собственные функции UIScrollViewDelegate.

Чтобы заставить parentVC реагировать на методы делегирования UIScrollView, вам придется создать пользовательский делегат внутри вашего customScrollView.

В момент вызова функции UIScrollViewDelegate вы также вызовете одну из своих функций делегата из пользовательского делегата. Таким образом, ваш parentVC будет реагировать в данный момент Вы этого хотите.

Это будет выглядеть примерно так.

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
}

Я надеюсь, что это полностью покрывает вашу проблему. Удачи.

Иногда имеет смысл присоединить несколько делегатов к виду прокрутки. В этом случае можно построить простой разделитель делегирования:

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

Затем просто установите экземпляр этого разделителя в качестве делегата представления прокрутки и присоедините любое число делегатов к разделителю. Все они примут участие в мероприятиях делегации. Некоторые предостережения применимы, например, предполагается, что все делегаты имеют один и тот же тип, иначе у вас возникнут проблемы с наивной реализацией respondsToSelector. Это не большая проблема, легко изменить реализацию, чтобы отправлять события делегирования только тем, кто их поддерживает.

Краткий ответ: Нет. делегаты, как правило, являются слабыми отношениями один-к-одному:

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

Иногда вы увидите шаблон дизайна "слушатель", который является формой делегатов один ко многим:

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

В вашем случае в UIScrollView нет хорошей точки публичного переопределения, которая позволяет подклассам указывать viewForZoomingInScrollView. Я бы не стал делать UIScrollView своим собственным делегатом, если это возможно. Вы могли бы сделать UIViewController UIScrollViewDelegate и заставить его предоставить