Установка делегата для пользовательского протокола препятствует методам UIScrollViewDelegate

#objective-c #cocoa-touch #ios #delegates #protocols

#objective-c #cocoa-touch #iOS #делегаты #протоколы

Вопрос:

Я использую пользовательский подкласс UIScrollView called ImageScrollView . Мне нужно знать, когда пользователь нажимает на вид прокрутки, поэтому я создал протокол. Я реализую протокол в своем RootViewController , и все выглядит нормально. Когда я его создаю, появляется предупреждение

Класс ‘ImageScrollView’ не реализует протокол ‘TapDetectingImageViewDelegate'».

После проверки init метода в ImageScrollView классе я вижу, что self.delegate = self; является причиной проблемы. Я объявляю себя делегатом для UIScrollView методов делегирования, но я также являюсь делегатом для своего собственного протокола (Делегат для моего протокола должен быть RootViewController , а не ImageScrollView ).

 - (id)initWithFrame:(CGRect)frame{
      if ((self = [super initWithFrame:frame])) {
         self.showsVerticalScrollIndicator = NO;
         self.showsHorizontalScrollIndicator = NO;
         self.bouncesZoom = YES;
         self.decelerationRate = UIScrollViewDecelerationRateFast;
         self.delegate = self;        
      }
      return self;
 }
  

Ребята, вы знаете, как я могу это решить? Или лучшая идея сообщить моему RootViewController , что пользователь нажал на UIScrollView / UIImage .

Объявление протокола в ImageScrollView.h

 @protocol TapDetectingImageViewDelegate <NSObject>

@optional
- (void)tapDetectingImageView:(ImageScrollView *)view gotSingleTapAtPoint:(CGPoint)tapPoint;

@end
  

Заголовочный файл класса, который его реализует

 #import <UIKit/UIKit.h>
#import "ImageScrollView.h"

@interface AppleScrollViewViewController : UIViewController <UIScrollViewDelegate, TapDetectingImageViewDelegate>{

    UIScrollView *pagingScrollView;
}

-(void)configurePage:(ImageScrollView *)page forIndex:(NSUInteger)index;
- (CGRect)frameForPageAtIndex:(NSUInteger)index;
- (CGRect)frameForPagingScrollView;
- (UIImage *)imageAtIndex:(NSUInteger)index;
- (NSString *)imageNameAtIndex:(NSUInteger)index;
- (CGSize)imageSizeAtIndex:(NSUInteger)index;
- (NSArray *)imageData;

@end
  

Метод протокола в классе .m, который его реализует

 -(void)tapDetectingImageView:(ImageScrollView *)view gotSingleTapAtPoint:(CGPoint)tapPoint{
    NSLog(@"SingleTap");
}
  

Комментарии:

1. Можете ли вы опубликовать объявление вашего протокола и .h для класса, который реализует протокол? Похоже, что подпись объявления метода в протоколе и реализация не совпадают.

2. Пока я публиковал материал, который вы просили, заметил, что я реализовал неправильный метод протокола в своем классе. Я внедрил правильный метод, и он регистрирует «Одно нажатие». Но я все еще получаю предупреждение. Есть идея?

Ответ №1:

Если вы хотите, чтобы контроллер представления был его делегатом, то не устанавливайте делегат в инициализаторе. При создании ImageScrollView экземпляра вам следует установить его на контроллер представления.

 ImageScrollView * aScrollView = [[ImageScrollView alloc] initWithFrame:aFrame];
aScrollView.delegate = self;
[..]
  

Если вы создаете это с помощью IB, то есть переименовываете имя класса a UIScrollView в ImageScrollView , вам придется создать для него выход, а затем установить делегат в viewDidLoad методе контроллера представления.

Однако при таком подходе существует проблема. Если ImageScrollView это подкласс a UIScrollView , как следует из названия, delegate свойство вида прокрутки теряется. Вы также должны принять это во внимание.

Комментарии:

1. Вот где я сейчас нахожусь. Мой протокол теперь работает, но свойство делегата scrollview потеряно. Знаете ли вы какой-либо обходной путь или подсказку?

2. Что вы имеете в виду, это потеряно? Как вы инициализируете объект? Как вы настраиваете делегат?

3. Вся конфигурация / внешний вид, которые я создал в классе ImageScrollView с помощью его методов делегирования (методы делегирования UIScrollView, поскольку ImageScrollView является подклассом UIScrollView), больше не работает. Похоже, что если мой протокол действительно работает, то UIScrollView — нет.

4. Объявите свой протокол следующим образом @protocol TapDetectingImageViewDelegate <UIScrollViewDelegate> .

5. В таком случае переименуйте delegate свойство в вашем ImageScrollView классе во что-то вроде imageScrollViewDelegate . Таким образом, вы можете создать различие. Для переменных делегата не должно быть имен delegate . В фреймворках Apple есть несколько таких экземпляров

Ответ №2:

У вас будет объявление RootViewController делегата в .h файле ImageScrollView ,

Измените имя корневого делегата на rootDelegate ;

В ImageScrollView.h

   RootViewControllerDelegate* rootDelegate;
  @property(nonatomic,assign) RootViewControllerDelegate* rootDelegate;
  

в файле ImageScrollView.m

 @synthesize rootDelegate;
- (id)initWithFrame:(CGRect)frame{
      if ((self = [super initWithFrame:frame])) {
         self.showsVerticalScrollIndicator = NO;
         self.showsHorizontalScrollIndicator = NO;
         self.bouncesZoom = YES;
         self.decelerationRate = UIScrollViewDecelerationRateFast;
         self.delegate = self;    
         // Root controller delegate.
         self.rootDelegate = self;            
      }
      return self;
 }
  

Комментарии:

1. Проблема, с которой я сталкиваюсь, заключается в том, что ImageScrollView объявляет протокол, и с помощью «self.delegate = self» предполагает, что он также должен реализовывать протокол, что совершенно неверно. ImageScrollView объявляет протокол, и мой ‘RootViewController’ должен его реализовать. Вот почему xcode выдает предупреждение в ImageScrollView. Есть идея?