Почему я должен объявлять в заголовке свойство, указанное протоколом, а не расширение класса (реализацию)

Итак, у меня есть протокол, который требует объявления свойства:

@protocol MyProtocol <NSObject>
@property MyView *myView;
@end

и объект, который ему соответствует:

@interface MyViewController : NSViewController <MyProtocol>
@end

Однако, если я объявлю свойство (указанное в протоколе) внутри файла реализации (расширение класса):

@interface MyViewController()
@property MyView *myView;
@end

Я получаю такую ​​ошибку:

Незаконное повторное объявление свойства в расширении класса MyViewController (атрибут должен иметь значение readwrite, а его основное значение должно быть только для чтения)

Кажется, есть два основных потока SO, которые обращаются к этому:
атрибут должен быть доступен для чтения и записи, а его основной должен быть доступен только для чтения
и
Невозможно объявить другое окно

Первый ответ ничего не объясняет

Во втором ответе говорится, что эту ошибку можно обойти, объявив свойство внутри заголовка; и увы

Заголовок

@interface MyViewController : NSViewController <MyProtocol>
@property MyView *myView;
@end

Реализация

@interface MyViewController()
@end

Это строится без ошибок.

Я также знаю, что когда вы объявляете @property внутри протокола, он не синтезируется автоматически.

Поэтому, если бы я хотел сохранить объявление @property внутри реализации, мне пришлось бы @synthesize его. И это тоже работает.


Итак, мой вопрос: почему объявление @property внутри заголовка по сравнению с файлом реализации имеет значение, если @property изначально был объявлен внутри протокола?

Я думал, что без протокола единственная разница в том, чтобы сделать @property общедоступным или частным. Но очевидно, что есть и другие вещи, которые случаются / не происходят, если вы объявляете @property в заголовке по сравнению с файлом реализации.


person A O    schedule 28.09.2015    source источник
comment
Поскольку вы публично заявляете, что ваш класс соответствует протоколу (в файле .h), вы также должны публично заявить, что у вас есть свойство. Если вы хотите, чтобы свойство было только частным, следуйте протоколу расширения класса, а не общедоступного интерфейса.   -  person rmaddy    schedule 28.09.2015
comment
Я все еще получаю эту ошибку: \, а также я не думаю, что смогу это сделать в любом случае, потому что другие мои объекты должны знать, что MyViewController соответствует _2 _--, и похоже, что никто не знает, что это так, если я соглашаюсь с расширением класса   -  person A O    schedule 28.09.2015
comment
Хорошо, тогда если вам нужно публично объявить протокол, то почему бы вам не объявить публично свойство?   -  person rmaddy    schedule 28.09.2015
comment
Да, я должен быть, но я думаю, я просто не понимаю, почему это важно, если я объявляю @property внутри заголовка или реализации, и почему, если я объявляю @property как readwrite в протоколе, но как readonly в реализации - - оно работает   -  person A O    schedule 28.09.2015
comment
Он должен быть общедоступным, поэтому он должен быть объявлен в интерфейсе (заголовке), а не в реализации.   -  person rmaddy    schedule 28.09.2015
comment
Извините, я вас раздражаю; а я не думаю, что это нужно указывать в шапке? Кажется, это проблема только с @property. У меня есть методы, объявленные в моем протоколе, и компилятор полностью согласен со мной, реализуя их без объявления в заголовке. Также я не понимаю, почему он волшебным образом работает, когда я добавляю свойства readwrite и readonly   -  person A O    schedule 28.09.2015


Ответы (1)


Не объявляйте свойство в любом месте вашего класса. Это уже заявлено в протоколе.

Не помещайте @property MyView *myView; ни в файлы MyViewController.m, ни в MyViewController.h.

Чтобы исправить предупреждение об "автоматическом синтезе свойств", вы просто добавляете:

@synthesize myView = _myView;

к реализации MyViewController или при необходимости добавьте явные методы получения и установки.

person rmaddy    schedule 28.09.2015
comment
Итак, я предполагаю, что, объявив свойство как readwrite в протоколе и readonly в реализации, компилятор по какой-то причине просто предполагает автоматически синтезировать свойство? - person A O; 28.09.2015
comment
В Xcode 7 вы не можете объявить свойство как доступное только для чтения (или чтение-запись) в расширении класса. - person rmaddy; 28.09.2015