2011-06-23 3 views
4

В следующем общем образце,Objective-C, декларация интерфейса со свойствами

//// 
@interface MyObject : NSObject 
{ 
@public 
    NSString * myString_; 
} 

@property (assign) NSString * myString; 
@end 

@implementation MyObject 
@synthesize myString = myString_; 
@end 
//// 

, почему объявляет myString_ в интерфейсе вообще?

Я спрашиваю, потому что мы все еще можем получить и установить myString в реализации с использованием self.myString, [self myString], self.myString = ... и [self setMyString:...] и на самом деле мы должны, если вместо того, чтобы это время сохраняется.

ответ

1

С современным временем выполнения Obj-C, объявляя, что ivar является скорее формальностью, чем чем-либо еще. Тем не менее, есть некоторые вещи управления памятью, которые нужно иметь в виду.

Во-первых, объявление свойства для типа объекта обычно равно retain, или для строк это может быть copy. В любом случае новый объект сохраняется.

Учитывая следующий код:

NSString *string = [[NSString alloc] init]; 
myString_ = string; 
self.myString = string; // If the property was retain or copy 

Второе задание будет течь; первый не будет. Это связано с тем, что свойство сохранит что-то, у которого уже есть счет сохранения 1, теперь он равен 2. Когда вы отпустите свойство в dealloc, счетчик будет равен 1, а не 0, поэтому он не будет выпущен. Однако с первым вариантом количество удержаний остается равным 1, поэтому dealloc переносит его на 0.

В вашем примере, оставляя свойство assign, сделайте декларацию ivar формальной.

5

Это вопрос предпочтения/конвенции для некоторых. По умолчанию, выполнив:

@property (assign) NSString * myString; 

... а затем:

@synthesize myString; 

... даст вам три вещи. Вы получаете метод сеттера, к которому можно получить доступ как self.myString = @"newValue" или [self setMyString:@"newValue"], метод getter, к которому можно получить доступ как NSString* temp = self.myString или NSString* temp = [self myString], и переменную экземпляра с именем myString, к которой можно получить доступ непосредственно внутри вашего класса (т. Е. Без прохождения через getter и setter) и используется для установки и получения значения свойства и который используется внутренне для возврата свойства.

Если вы хотите, вы можете сделать @synthesize myString = someOtherVarName, и тогда вы все равно получите сеттер и добытчик так же, как и раньше, но вместо переменного в myString экземпляре переменные someOtherVarName экземпляра используются для резервного имущества, а не myString переменных создаются.

Итак, зачем использовать более подробный синтаксис? Никогда не бывает случая, когда вы это делаете, но некоторые люди предпочитают делать это при работе со свойствами, объявленными retain или copy. Причиной этого является то, что установка объявленного свойства retain или copy с помощью его сгенерированного метода сеттера будет влиять на счет сохранения установленного/не заданного объекта. То же самое происходит при непосредственном доступе к переменной экземпляра.

Таким образом, путем наложения переменной экземпляра на что-то еще, вы можете сделать различие в коде по строкам «все, что делает xxx.myString = Y, изменяя количество удержаний, в то время как все, что делает someOtherVarName = Y, не является». Опять же, это не обязательно делать, но некоторые люди предпочитают это делать.

+1

+1; Я хотел бы добавить, что '@ synhesize' будет просто _complete_ классом с ivar, getter и setter: если вы сами определите их, они будут иметь преимущество перед автоматической реализацией. – zneak

2

Вы должны уметь пропустить его. Современные компиляторы позволяют это.

Когда вы определяете свойство, вы фактически объявляете, как методы getter и setter создаются для конкретной переменной экземпляра. Раньше ему нужно было указать переменную экземпляра, чтобы вы ее объявили. Это также позволило названию свойства отличаться от имени переменной экземпляра через @synthesize myProperty = myIVar;. Теперь вам не нужно это делать, поскольку современные компиляторы генерируют переменную экземпляра для вас.

Синтаксис точки на самом деле удобная вещь, как вы бы заметили. Он напрямую не ссылается на переменную экземпляра, но методы myProperty и setMyProperty:. Вы даже можете позвонить myArray.count, где count не является собственностью (я бы не рекомендовал его, даже если многим понравилось).

Несмотря на то, что существует разница между двумя, промежуток, кажется, медленно закрывается.

2

Это просто проблема с точкой зрения. Если вы напрямую обращаетесь к ivar, вы получаете доступ к нему внутри. Если вы используете свойство, вы не получаете доступ к ivar (семантически). Вы используете метод доступа к объекту. Таким образом, вы обрабатываете self как внешний объект, внутренний - неизвестен.

Это инкапсуляция проблема объектно-ориентированной парадигмы.

И я рекомендую некоторые трюки при использовании свойств.

  1. Объявление ivar необязательно, не требуется. Компилятор будет генерировать его автоматически.
  2. Вы должны установить ivar как @protected или @private, чтобы инкапсулировать его правильно. (по крайней мере, нет разумных причин)
  3. Я рекомендую использовать nonatomic, если вам не нужен блокировка резьбы при доступе к объекту. Блокировка потоков значительно снижает производительность и может вызвать странное поведение в кодах параллельного выполнения.

Вы можете использовать этот код, чтобы сделать то же самое.

@interface MyObject : NSObject 
@property (assign,nonatomic) NSString * myString; 
@end 

@implementation MyObject 
@synthesize myString; 
@end 

И это будет примерно примерно такое.

@interface MyObject : NSObject 
{ 
    @private 
    NSString* myString; // Ivar generated automatically by compiler 
} 
@end 

@implementation MyObject 
// Methods with thread synchronization locking generated automatically by compiler. 
- (NSString*)myString { @synchronized(self) { return myString; } } 
- (void)setMyString:(NSString*)newMyString { @synchronized(self){ myString = newMyString; } } 
@end 

На самом деле, я не уверен насчет блокировки синхронизации с assign директивы поведения, но это всегда лучше, установив его nonatomic явно. Компилятор может оптимизировать его с помощью команды атомарного управления вместо блокировки.

Здесь ссылка на документ о свойствах: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html%23//apple_ref/doc/uid/TP30001163-CH17

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