2009-04-13 2 views
24

Я пытаюсь объявить свойства, которые только для внутреннего использования в Private категории, как например:Скрытие свойств из публичного доступа

@interface BarLayer (Private) 

@property (readwrite, retain) MenuItemFont *menuButton; 
@property (readwrite, retain) Menu   *menuMenu; 
@property (readwrite, retain) LabelAtlas *messageLabel; 

@end 

Теперь я пытаюсь выяснить, где именно я должен @synthesize тех.

Я пробовал:

@implementation BarLayer (Private) 

@synthesize menuButton  = _menuButton; 
@synthesize menuMenu  = _menuMenu; 
@synthesize messageLabel = _messageLabel; 

@end 

Здесь компилятор жалуется:

@synthesize не допускается осуществления той или иной категории в

Так что я попытался положить его в моем BarLayer реализации, но здесь он не находит деклараций в интерфейсе BarLayer.

нет декларации имущества «кнопку MENU» найден в интерфейсе

Что бы правильный способ быть?

+0

Я думаю, вы должны изменить правильный ответ на этот вопрос, пожалуйста, проверьте мой ответ: http://stackoverflow.com/a/7400441/662605 считает – Daniel

ответ

1

На самом деле, с последним компилятором LLVM эта проблема может быть решена намного лучше. скрыть как можно больше о ваших свойствах, было объявить ваши переменные в вашем .h, префикс их с помощью _, объявить свойство в расширении класса в частном .m и @synthesize это свойство в вашей @implementation.

С последним LLVM (3.0) вы можете идти еще дальше, скрывая все о вашей собственности, включая поддержку ivar. Его объявление может быть перемещено в .m и даже опущено там, и в этом случае он будет синтезирован компилятор (спасибо Ivan):

Автомобиль.ч:

@interface Car : NSObject 

- (void)drive; 

@end 

Car.m:

@interface Car() 

@property (assign) BOOL driving; 

@end 

@implementation Car 
@synthesize driving; 

- (void)drive { 

    self.driving = YES; 
} 

@end 
+0

Вам даже не нужно декларировать поддержку ivar. Он автоматически синтезируется. –

1

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

Вы можете объявить свойства, полученные из уже существующих классов. Например. Если у вашего класса есть firstName и lastName, вы можете объявить объект под названием fullName в категории @implementation.

@interface Bar (Private) 
@property (readonly) NSString *fullName; // Note readonly, you have nothing to write to. 
@end 

Однако, вы не можете просто @synthesize это свойство, вы должны написать свой собственный аксессор, потому что компилятор не имеет ни малейшего представления, где вы хотите, чтобы получить это значение из.

@implementation Bar (Private) 
- (NSString *)fullName { 
    NSString *returnString = [NSString stringWithFormat:@"%@ %@", 
          self.firstName, self.lastName]; 
} 

От дизайн класса точки зрения, я не уверен, что идея частной собственности имеет смысл: Я лично считаю, свойств, как то, что подвергается публично класс.

Вы можете использовать ключевое слово @private в классе BarLayer, чтобы хотя бы добавить некоторую защиту к его состоянию.

42

Вы не можете использовать @synthesize с категорией.

Вы могут сделать это с расширением класса (а.к.а. анонимной категории), которая только категория без названия которого методы должны быть реализованы в главном @implementation блоке для этого класса. Для вашего кода просто измените «(частный)» на «()» и используйте @synthesize в основном блоке @implementation вместе с остальной частью вашего кода для этого класса.

См. the Apple docs on extensions для получения более подробной информации. (По-видимому, это новое в Mac OS 10.5.)

РЕДАКТИРОВАТЬ: Пример:

// Main interface (in .h) 
@interface Foo : NSObject 
- (void)bar; 
@end 

// Private interface (in .m, or private .h) 
@interface Foo() 
@property (nonatomic, copy) NSString *myData; 
@end 

@implementation Foo 
@synthesize myData; // only needed for Xcode 4.3 and earlier 
- (void)bar { ... } 
@end 

Другим решение, которое намного больше работы, заключается в использовании objc_setAssociatedObject и objc_getAssociatedObject фальсифицировать дополнительный переменный экземпляр. В этом случае вы можете объявить их как свойства и сами реализовать сеттеры и геттеры, используя вышеописанные методы выполнения objc_ *. Подробнее об этих функциях см. В разделе the Apple docs on Objective-C runtime.

+1

+1 для расширения пути. Я также написал краткое сравнение различных типов категорий в этом ответе http://stackoverflow.com/questions/360968/category-usage-in-objective-c/361140#361140 – Abizern

+0

@Abizern - хорошая ссылка. Вы также можете связать этот ответ с этим вопросом для получения дополнительной информации о свойствах. –

+0

Стоит отметить: по-видимому, URL-адрес документов для расширений изменился на: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html –

8

Скотт Стивенсон (http://theocacao.com/) объясняет в своем блоге "A Quick Objective-C 2.0 Tutorial: Part II" как получить Общедоступные свойства с частным сеттеров. Следуя его совету, вы получите свойство, доступное только для чтения, но имеющее частный сеттер, который можно использовать с точечным синтаксисом. Надеюсь, что это помогает ...

12

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

Следующая информация исходит от http://www.friday.com/bbum/2009/09/11/class-extensions-explained/

" Синтез причины был запрещен в категориях, потому что синтез требует хранения, и не было возможности эффективно объявлять хранение в категории, и было сочтено неприемлемым, чтобы позволить категории синтезировать методы, которые затем могли бы использовать ивары класса. Слишком хрупкие и уродливый.

Однако было также очевидно, что было бы возможно объявить свойство, которое было открыто для чтения, но чья реализация была прочитана для целей внутри-класса или рамки.

Еще одно требование состоит в том, что синтез таких свойств должен всегда иметь возможность синтезировать как сеттер, так и геттер естественно и точно. В частности, при объявлении свойства как атомарного, разработчик не может правильно вручную написать только 1/2 пары установителей геттера; инфраструктура блокировки не открывается и, таким образом, нет возможности гарантировать атомарность в такой ситуации.

Расширения в классе адресованы этой проблеме элегантно.

В частности, вы можете объявить свойство как:

@interface MyClass : NSObject 
@property(readonly) NSView *targetView; 
@end 

, а затем и в файле реализации:

@interface MyClass() 
@property(readwrite) NSView *targetView; 
@end 

@implementation MyClass 
@synthesize targetView; 
@end 

Конечный результат? Свойство, которое открыто для чтения, но конфиденциально читается без открытия свойств, вплоть до всей хрупкости, связанной с категориями ».

+0

Спасибо за ссылку. Это действительно полезно. – thesummersign

2

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

Я написал post about it here, если кому-то хотелось бы получить более подробную информацию.

Существует еще один вопрос, который затрагивает эту тему, but it's pretty scant on the details.

Приветствие

Смежные вопросы