Что означает это предупреждение о значении свойств objective-c?

Начиная с обновления до Xcode 5.1, я начинаю видеть следующее предупреждение в некотором коде, используемом моим проектом. Я пытаюсь понять, что это значит.

Предупреждение: Auto property synthesis will not synthesize property 'responseHeader' because it is 'readwrite' but it will be synthesized 'readonly' via another property

Код, в котором он встречается, в файле .m:

@interface S3Response ()
@property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
@end

Предыдущее объявление свойства в файле .h:

@property (nonatomic, readonly) NSDictionary *responseHeader;

Для этого свойства нет инструкции @synthesize, а также responseHeader или setResponseHeader, определенные как методы. Однако существует четкое определение ivar с именем responseHeader.

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

Что означает это предупреждение, и что мне с этим делать?

Ответы

Ответ 1

Этот код, как представляется, из AWS SDK для iOS, и S3Response является подклассом AmazonServiceResponse.

Открытый AmazonServiceResponse интерфейс определяет свойство только для чтения

@interface AmazonServiceResponse:NSObject
// ...
@property (nonatomic, readonly) NSDictionary *responseHeader;
@end

который переопределяется как чтение и запись в расширении класса в файле реализации:

@interface AmazonServiceResponse ()
@property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
@end

Теперь подкласс S3Response также хочет получить доступ на чтение и запись к этому свойству, и поэтому также определяет в расширении класса его файл реализации:

@interface S3Response ()
@property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
@end

Компилятор жалуется, потому что - при компиляции "S3Response.m" - он не знает что сеттер для свойства существует в суперклассе (он не читает файл реализации суперкласса в этой точке). Также компилятор не может просто синтезируйте сеттер в подклассе, потому что он не может не знать, что свойство резервируется переменной экземпляра в суперклассе.

Но вы знаете, что сеттер будет сгенерирован, поэтому вы можете удалить предупреждение добавление объявления @dynamic в реализацию подкласса:

@implementation S3Response
@dynamic responseHeader;
...

@dynamic является "обещанием" компилятору, что все необходимые методы доступа будут быть доступным во время выполнения.

Ответ 2

Проблема здесь заключается в следующем.

По умолчанию, если вы не произвольно записываете право собственности (слабый/сохраняете/сильный/назначать), xCode будет автоматически проверять тип. Поэтому в случае NSDictionary он будет сильным. Таким образом, в интерфейсе вы будете иметь

@property (nonatomic, readonly, strong) NSDictionary *responseHeader;

Тогда это будет противоречить вашему определению частной реализации

@property (nonatomic, readwrite, retain) NSDictionary *responseHeader;

Компилятор не соответствует сильным и сохраняется при синтезе свойств, хотя формально это одно и то же.

Чтобы вылечить ситуацию, вы можете записать сохранение в обоих случаях или, вернее, не писать вообще. Он будет сильным по умолчанию в обоих определениях.