Почему компилятор предупреждает при повторном выделении свойства readwrite базового класса как readonly в подклассе? - PullRequest
6 голосов
/ 22 августа 2011

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

У меня есть базовый класс с общедоступным свойством readwrite и подклассом, в котором я повторно объявляю свойство только для чтения.У подкласса также есть расширение класса, которое снова объявляет свойство как readwrite, чтобы получить общий шаблон Objective-C "public readonly, private readwrite".Однако я получаю следующее предупреждение компилятора:

warning: Semantic Issue: Attribute 'readonly' of property 'foo' restricts attribute 'readwrite' of property inherited from 'Base'

Я использую Xcode 4.1 build 4B110 с LLVM 2.1 (хотя LLVM GCC4.2 и GCC4.2 выдают одно и то же предупреждение) на 10.7.

Вот урезанный пример с предупреждением компилятора:

#import <Foundation/Foundation.h>

@interface Base : NSObject
@property (nonatomic, readwrite) BOOL foo;
@end

@implementation Base
@dynamic foo;
@end

// Subclass
@interface Sub : Base
@property (nonatomic, readonly) BOOL foo;
@end

// Class extension 
@interface Sub ()
@property (nonatomic, readwrite) BOOL foo;
@end

@implementation Sub
@dynamic foo;  // it warns with @synthesize as well
@end

Вот соответствующий отрывок из Apple Язык программирования Objective-C :

Переопределение свойства

Вы можете повторно объявить свойство в подклассе, но (за исключением чтения только для чтения и записи) вы должны полностью повторить его атрибуты в подклассах.То же самое относится и к свойству, объявленному в категории или протоколе - хотя свойство может быть повторно объявлено в категории или протоколе, атрибуты свойства должны повторяться полностью.

Если вы объявите свойство в одном классе какТолько для чтения вы можете переопределить его как readwrite в расширении класса (см. «Расширения»), в протоколе или в подклассе (см. «Подклассы со свойствами»).В случае переопределения расширения класса тот факт, что свойство было объявлено перед любым оператором @synthesize, вызывает синтезатор сеттера.Возможность повторного объявления свойства «только для чтения» как «чтение / запись» включает два общих шаблона реализации: изменяемый подкласс неизменяемого класса (все примеры - NSString, NSArray и NSDictionary) и свойство, имеющее общедоступный API, доступный только для чтения, ночастная реализация readwrite внутри класса.В следующем примере показано использование расширения класса для предоставления свойства, которое объявлено в общедоступном заголовке как доступное только для чтения, но переобъявлено в частном порядке как чтение / запись.

Я переобозначаю общедоступные свойства readonly в расширениях классавсе время, но я думаю, у меня никогда не было причин делать это подклассом.Однако, если я не читаю это неправильно, параграфы выше, кажется, указывают, что это кошерно.Может кто-нибудь объяснить мне и / или примирить очевидный конфликт между документами и компилятором?

Почему я хочу это сделать?Моя ситуация в реальном мире, конечно, более сложная.Я могу внести изменения в конструкцию, чтобы обойти это, если необходимо, но это выглядело как альтернатива с наименьшим трением (необходимость делать это вообще обусловлена ​​другими изменениями).

1 Ответ

12 голосов
/ 22 августа 2011

В нем говорится, что вы можете переопределить свойство readonly как readwrite, но вы делаете обратное.Вы не можете / не должны этого делать, потому что это возможно:

Sub* s = [[[Sub alloc] init] autorelease];
Base* b = s; 
b.foo = YES; //legal for `Base` objects, but not legal for `Sub` objects

Это нарушение принципа замены Лискова .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...