Переопределение свойств, соответствующих протоколам

Кажется, я получаю новую ошибку при использовании LLVM Compiler 2.0, чего у меня раньше не было.

У меня есть протокол под названием DTGridViewDelegate, который определяется как:

@protocol DTGridViewDelegate <UIScrollViewDelegate>

У меня есть свойство, называемое delegate в DTGridView (подкласс UIScrollView, который сам имеет свойство delegate). Это определяется как:

@property (nonatomic, assign) IBOutlet id<DTGridViewDelegate> delegate;

Теперь я получаю сообщение:

DTGridView.h:116:63: error: property type 'id<DTGridViewDelegate>' is incompatible with type 'id<UIScrollViewDelegate>' inherited from 'UIScrollView'

Поскольку я сказал, что DTGridViewDelegate соответствует UIScrollViewDelegate, я думал, что это будет нормально переопределить это свойство таким образом, и действительно, это первый компилятор, предлагающий проблему.

Я исправил ошибку, объявив свойство как таковое:

@property (nonatomic, assign) IBOutlet id<DTGridViewDelegate, UIScrollViewDelegate> delegate;

Мне интересно, это проблема компилятора?

Ответ 1

Ваша установка выглядит так же, как и в UITableView, наследующем от UIScrollView. Протокол UITableViewDelegate наследуется от протокола UIScrollViewDelegate.

Я установил следующее, которое компилируется отлично:

// .h
@protocol ParentClassDelegate
-(NSString *) aDelegateMethod;
@end

@interface ParentClass : NSObject {
    id delegate;
}
@property(nonatomic, assign) IBOutlet id <ParentClassDelegate> delegate;
@end

//.m
@implementation ParentClass
@synthesize delegate;

-(id) delegate{
    return @"Parent delegate";
}//-------------------------------------(id) delegate------------------------------------

-(void) setDelegate:(id)someObj{
    delegate=someObj;
}//-------------------------------------(id) setDelegate------------------------------------
@end

//.h
@protocol ChildClassDelegate <ParentClassDelegate>
-(NSArray *) anotherDelegateMethod;
@end

@interface ChildClass : ParentClass{
}
@property(nonatomic, retain) IBOutlet id <ChildClassDelegate> delegate;
@end

//.m
@implementation ChildClass
//@synthesize delegate;

-(id) delegate{
    return @"childDelegate";
}//-------------------------------------(id) delegate------------------------------------

-(void) setDelegate:(id)someObj{
    delegate=someObj;
}//-------------------------------------(id) setDelegate------------------------------------

@end

Не уверен, что вызывает вашу проблему. Я хотел бы отметить, что в заголовке протокол UITableViewDelegate выглядит следующим образом:

@protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>

... поэтому, возможно, компилятор иногда любит вещи более четко.

Я бы предложил чистую и сборку. Это решает много проблем.

Ответ 2

Поскольку формальной спецификации языка Objective-C нет, невозможно сказать, правильно ли работает компилятор. Все, что мы можем сказать, заключается в том, что Apple gcc, похоже, не имеет проблемы с вышеупомянутым сценарием, хотя она концептуально необоснованна, поскольку она может сломать Liskov substitution, так как delegate covariant от UIScrollView до DTGridView (хотя ковариация - такая же проблема). Что произойдет, если вы передадите код DTGridView в ожидающий UIScrollView код, который затем перешел к установке delegate объекту, который соответствует UIScrollViewDelegate, но не DTGridViewDelegate?