Несколько делегатов на один объект?
У меня есть UIScrollView
, который мне нужен для подкласса, и внутри подкласса мне нужно прикрепить UIScrollViewDelegate
, чтобы я мог реализовать метод viewForZoomingInScrollView
.
Тогда у меня есть UIViewController
, где мне нужно создать экземпляр объекта этого подкласса UIScrollView
, который я создал, и я также хотел бы сделать UIViewController a UIScrollViewDelegate
для этого объекта, чтобы я мог реализовать scrollViewDidZoom
в этом классе UIViewController
.
Как можно сделать один объект двумя делегатами? (Я знаю, что я мог бы просто иметь одного делегата и просто использовать оба метода там, но для целей дизайна я хотел бы сделать это так, как я упоминаю).
Ответы
Ответ 1
Вам не нужен объект с двумя делегатами. Вы хотите, чтобы ваша customScrollView несла ответственность за свои собственные функции UIScrollViewDelegate.
Чтобы ваш родительский VC ответил на методы делегирования UIScrollView, вам также придется создать пользовательский делегат внутри вашего customScrollView.
В настоящее время вызывается функция UIScrollViewDelegate, вы также вызываете одну из своих функций делегата из своего пользовательского делегата. Таким образом, ваш родительский VC будет отвечать в тот момент, когда вы этого хотите.
Это будет выглядеть примерно так.
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
}
Я надеюсь, что это полностью покрывает вашу проблему.
Удачи.
Ответ 2
Иногда имеет смысл прикрепить нескольких делегатов к просмотру прокрутки. В этом случае вы можете создать простой разделитель делегирования:
// 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
. Это не большая проблема, ее легко изменить реализацию, чтобы отправлять события отправки только тем, кто их поддерживает.
Ответ 3
Короткий ответ: нет. Делегаты обычно являются слабым отношением один к одному:
@property (nonatomic, weak /*or assign*/) id<MyViewDelegate> delegate;
Иногда вы увидите шаблон дизайна "слушатель", который является делегатом "один ко многим":
- (void) addListener:(id<MyViewListener>)listener;
- (void) removeListener:(id<MyViewListener>)listener;
В вашем случае в UIScrollView не отображается хорошая точка переопределения public, которая позволяет подклассам указывать viewForZoomingInScrollView. Я бы не стал делать UIScrollView своим собственным делегатом, если это возможно. Вы можете сделать UIViewController UIScrollViewDelegate и предоставить ему viewForZooming. Или вы можете сделать подкласс промежуточного представления, который использует UIScrollView, предоставляет viewForZooming и пересылает другие методы делегата вверх.
Ответ 4
Я не думаю, что у вас могут быть два UIScrollViewDelegate
делегата, которые напрямую связаны с одним и тем же объектом.
Что вы можете сделать, так это наличие двух делегатов, связанных цепочкой. I.e., вы соединяете одного делегата с другим, затем передаете предыдущие сообщения вперед, когда они не могут обращаться с ними напрямую.
В любом случае, я думаю, что мне не хватает всего, чтобы полностью предложить решение, а именно причину, по которой вам нужен второй делегат, и не может делать это всегда через один делегат. Другими словами, я думаю, что могут быть альтернативные проекты, которые бы избегали необходимости в двух делегатах.
Ответ 5
Вот еще одна потенциальная проблема с тем, что вы пытаетесь сделать...
Допустим, у вас есть два экземпляра UIScrollView и один объект делегата. В объекте делегата вы переопределяете scrollViewDidScroll (UIScrollView *): метод протокола UIScrollViewDelegate.
Внутри метода вы хотите получить доступ к значению свойства contentOffset обоих представлений прокрутки, потому что, возможно, у вас есть два смежных представления коллекций, и вы пытаетесь получить путь индекса элемента в центре представления коллекции, чтобы получить значения свойств, связанных с этими двумя элементами (подумайте UIDatePicker).
В таком случае, чем вы отличаетесь между видами прокрутки? Свойство scrollView относится только к одному представлению прокрутки; но, даже если это относится к обоим, как вы получаете значение их соответствующих свойств contentOffset?
Теперь вы можете сказать: "Я могу создать IBOutlet для обоих и использовать их назначенные ссылки вместо свойства scrollView в методе делегата, такого как self.collectionViewFirst.contentOffset и self.collectionViewSecond.contentOffset, и игнорировать свойство scrollView метод делегата.
Проблема заключается в следующем: это свойство не сохраняется. Доступно только при вызове метода делегата. Зачем? Потому что там только один объект делегата и только одно свойство contentOffset. При прокрутке другого вида прокрутки значение свойства contentOffset будет меняться и не будет отражать смещение содержимого любого другого вида прокрутки, кроме последнего прокручиваемого.
Плохо практиковать то, что вы пытаетесь сделать, даже если описанный выше случай (или случай, подобный этому) не относится к вашей ситуации. Помните: написание кода касается обмена кодом. Неправильный код отправляет сообщение другим, что снижает вашу репутацию.
Ответ 6
Здесь элегантное решение с участием двух делегатов:
-
Пользовательский класс прокрутки LTInfiniteScrollView подклассы UIView
(не UIScrollView
) и добавляет UIScrollView
в качестве ребенок. LTInfiniteScrollView устанавливает себя как делегат этого UIScrollView
.
-
LTInfiniteScrollView определяет собственное свойство delegate
и протокол. Поскольку LTInfiniteScrollView не подклассы UIScrollView
, не существует существующего свойства delegate
, с которым можно было бы столкнуться.