Подтвердить что ты не робот

Как продлить протокол для делегата в объекте 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'.

4b9b3361

Ответ 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];