Как продлить протокол для делегата в объекте C, а затем подклассифицировать объект, требующий соответствующего делегата
Я хочу подклассировать UITextView и отправить новое сообщение делегату. Поэтому я хочу расширить протокол делегата. Каков правильный способ сделать это?
Я начал с этого:
Интерфейс
:
#import <Foundation/Foundation.h>
@class MySubClass;
@protocol MySubClassDelegate <UITextViewDelegate>
- (void) MySubClassMessage: (MySubClass *) subclass;
@end
@interface MySubClass : UITextView {
}
@end
реализация:
#import "MySubClass.h"
@implementation MySubClass
- (void) SomeMethod; {
if ([self.delegate respondsToSelector: @selector (MySubClassMessage:)]) {
[self.delegate MySubClassMessage: self];
}
}
@end
однако я получаю предупреждение: '-MySubClassMessage:' not found in protocol(s)
.
У меня был один способ работы, когда я создал свой собственный ivar для хранения делегата, а затем сохранил делегат с помощью [super setDelegate]
, но это показалось неправильным. возможно, нет.
Я знаю, что могу просто пропустить id и пройти, но моя цель - убедиться, что компилятор проверяет, что любой делегат, предоставленный MySubClass, соответствует протоколу MySubClassDelegate.
К дальнейшему clairfy:
@interface MySubClassTester : NSObject {
}
@implementation MySubClassTester
- (void) one {
MySubClass *subclass = [[MySubClass alloc] init];
subclass.delegate = self;
}
@end
выдаст предупреждение: class 'MySubClassTester' does not implement the 'UITextViewDelegate' protocol
Я хочу, чтобы это вызвало предупреждение о том, что вместо этого не выполняется протокол 'MySubClassDelegate'.
Ответы
Ответ 1
UITextView
определяет delegate
как
@property(nonatomic, assign) id<UITextViewDelegate> delegate
означает, что он соответствует UITextViewDelegate
, и что компилятор проверяет. Если вы хотите использовать новый протокол, вам необходимо переопределить delegate
, чтобы он соответствовал вашему протоколу:
@interface MySubClass : UITextView {
}
@property(nonatomic, assign) id<MySubClassDelegate> delegate
@end
Компилятор не должен давать больше предупреждений.
[Обновить по fess]
... С этим компилятор будет предупреждать, что аксессоры должны быть реализованы... [Я реализовал это:]
-(void) setDelegate:(id<MySubClassDelegate>) delegate {
[super setDelegate: delegate];
}
- (id) delegate {
return [super delegate];
}
"
[Мое обновление]
Я считаю, что он должен работать, если вы только делаете объявление @dynamic
вместо переопределения метода, поскольку реализация уже существует:
@dynamic delegate;
Ответ 2
Для всех, кого это интересует, это можно сделать просто так (для примера, подкласса UIScrollView):
@protocol MySubclassProtocol <UIScrollViewDelegate>
@required
-(void)myProtocolMethod;
@end
@interface MySubClass : UIScrollView
@property (nonatomic, weak) id <MySubclassProtocol> delegate;
Самая важная деталь здесь - это часть между < > после имени вашего протокола, которое, в простой форме, сигнализирует о расширении этого протокола.
В вашей реализации все, что вам нужно сделать, это:
@synthesize delegate;
И все готово.
Ответ 3
Учитывая, что MySubClassMessage: не является обязательным, вы должны иметь возможность сделать простой:
- (void) SomeMethod {
SEL delegateSelector = @selector(MySubClassMessage:);
if ([self.delegate respondsToSelector:delegateSelector]) {
[self.delegate performSelector:delegateSelector withObject:self];
}
}
Компилятор должен по-прежнему проверять соответствие класса реализации вашему протоколу (или, по крайней мере, претендовать на него в заголовке), и вы не получите описанную вами ошибку.
Ответ 4
Вам нужно расширить протокол super:
@protocol MYClassProtocol <SuperClassProtocol>
-(void)foo;
@end
после этого НЕ НЕ (!!!) создайте @property для делегата, иначе вы переопределите исходный объект делегата, но просто переопределите метод:
- (id<MYClassProtocol>)delegate
{
return (id<MYClassProtocol>)[super delegate];
}
теперь вы можете использовать делегат классическим способом:
[self.delegate foo];
[self.delegate someSuperClassDelegateMethod];