Objective-C, объявления интерфейса со свойствами - PullRequest
4 голосов
/ 23 июня 2011

В следующем общем примере

////
@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:...], и фактически мы должны, если вместо этого оно сохраняется.

Ответы [ 4 ]

5 голосов
/ 23 июня 2011

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

@property (assign) NSString * myString;

... с последующим:

@synthesize myString;

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

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

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

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

2 голосов
/ 23 июня 2011

Это просто проблема с точки зрения. Если вы обращаетесь к 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

2 голосов
/ 23 июня 2011

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

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

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

Хотя между этими двумя понятиями есть разница, разрыв, похоже, медленно сокращается.

1 голос
/ 23 июня 2011

В современной среде выполнения Obj-C объявление ивара является более формальным, чем все остальное.Однако следует помнить о некоторых вещах, связанных с управлением памятью.

Во-первых, объявление свойства для типа объекта обычно 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 формальным.1015 *

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