#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. Есть идея?