Разница между свойством класса mVar и переменной экземпляра self.mVar - PullRequest
4 голосов
/ 17 февраля 2010

Я немного запутался в разнице между доступом к переменной экземпляра через себя или просто по имени (при работе внутри класса).

Например, возьмите этот класс:

//In .h file:
@interface Register : NSObject {
    NSString *mName;
}

- (id) initWithName:(NSString *) name;

//In .m file:
- (id) initWithName:(NSString *)name
{
    if (self == [super init])
    {
        mName = name;
    }
    return self;
}

В чем разница между доступом к переменной экземпляра через

self.mName = name;

против

mName = name;

Это не @property и не @ sythenize'd.

Скажите, что это так, согласно этому примеру:

//In .h file:
@interface Manange_My_ViewsViewController : UIViewController { 
    IBOutlet UILabel *countLabel;
}

@property (nonatomic, retain) IBOutlet UILabel *countLabel;

//In .m file:
@synthesize countLabel;

- (void) updateLabel:(NSUInteger)count
{
    countLabel.text = [NSString stringWithFormat:@"%d", count];
}

Но, скажем, я обращался к countLabel как:

self.countLabel

Какая разница?

Редактировать: третий пример для ответа пользователя: Скажи, что iVar не был IBOutlet:

//In .h file:
@interface Fake : NSObject {
    NSString *mVar;
}
@property (nonatomic, retain) NSString *mVar;

//In .m file:
 @synthesize mVar;

 mVar = @"";

VS

 self.mVar = @"";

Или это то же самое - что в первом случае мы обращаемся к фактической переменной экземпляра, а во втором - через автоматически созданный установщик (через @synthesize)?

Спасибо всем!

Редактировать: Обновление в ответ на Питера Хоси ...

То есть, вы думаете, что конвенция mVarName плохая? Я взял это из моих дней C ++.

А как быть с делом, когда вы это делаете?

-(void) someMethod:(int) x
{
    x = x;
}

Вы не можете этого сделать (скажем, 'x' также является переменной класса)

Но вы можете сделать:

-(void) someMethod:(int) x
{
    mX = x;
}

Но вы говорите, что лучше сделать:

-(void) someMethod:(int) x
{
    self.x = x;
}

Ответы [ 3 ]

7 голосов
/ 17 февраля 2010

В чем разница между доступом к переменной экземпляра через

self.mName = name;

против

mName = name;

Первый - это синтаксис доступа к свойству. Он преобразуется в сообщение доступа к объекту (в данном случае self). То есть этот оператор неявно переводится в этот оператор выражения сообщения:

[self setMName:name];

(Неудобные имена аксессоров, подобные тому, почему «mName» является плохим именем для свойства. Существует синтаксис объявления свойства, чтобы обойти это, позволяя вам назвать свойство «name» и переменную вашего экземпляра «mName» и отобразить одно из них). к другому.)

Второй пример напрямую обращается к переменной экземпляра - сообщение доступа отсутствует.

Это не @property и не @ sythenize'd.

Скажи, что это все же, ...

Если для класса не объявлено свойство с именем «mName», то вы не можете использовать синтаксис доступа к свойству для доступа к свойству с этим именем в экземпляре этого класса.

И не имеет значения, синтезируете ли вы методы доступа, передаете их вручную суперклассу с помощью @dynamic или определяете их самостоятельно. Вот как объект будет реагировать на сообщение доступа, но сообщение доступа, генерируемое компилятором, не будет отличаться (поскольку доступ к свойству может быть так же легко получен извне класса, как и внутри него).

Скажите, что iVar не был IBOutlet:

Это не имеет значения. IBOutlet означает только что-либо для IB. Все остальное не волнует.

Фактически, IBOutlet в настоящее время является просто макросом, который расширяется до нуля. После предварительной обработки кода слово «IBOutlet» больше не существует, поэтому компилятор его никогда не видит. Вот как мало что это меняет во всем, кроме IB: вообще ничего.

Изменить в ответ на вопрос редактировать

Я сказал, mName неверно как имя свойства из-за имен доступа, которые следуют из него. Имя переменной экземпляра - это отдельная проблема, тем более что свойство и ivar не обязательно должны иметь одно и то же имя.

Для переменной, будь то переменная экземпляра или локальная переменная, выбор name или m_name или mName - это выбор стиля.

someMethod: обычно является аксессором, setX:. В этом методе self.x = x, то есть [self setX:x], вызывает бесконечную рекурсию. Так что не делай этого.

Когда someMethod: не является аксессором (или init или dealloc), использование свойства просто прекрасно и обычно предпочтительнее. Однако в этом случае вы вряд ли дадите одному из его аргументов то же имя, что и переменной экземпляра. Когда такой случай может произойти, назовите локальную переменную более конкретно, потому что ее цель более конкретна. Это тоже вопрос стиля.

Когда это метод доступа, я называю локальную переменную newX, назвав переменную экземпляра так же, как свойство x. Это мой личный стиль; Как я уже сказал, назовите свойство x, ivar mX и локальную переменную x тоже хорошо (за исключением чрезмерной краткости этого примера).

3 голосов
/ 17 февраля 2010

ОК, в первую очередь это основное отличие:

mVar = var;

Это просто изменение значения. Вот и все.

self.mVar = var;

Это эквивалентно:

[self setMVar:var];

Другими словами, один вызывает метод, другой - нет. Использование синтаксиса @property может дать вам действительно полезные преимущества. Например, вы получаете соответствие код-значение бесплатно. Это означает, что другой объект может наблюдать свойство mVar этого объекта и автоматически получать уведомление при каждом его изменении без каких-либо действий . Вы не получите это, если вы просто получите доступ к ivar напрямую. (Если, конечно, вы не реализуете это сами. Но зачем вам это делать?)

Вы также получаете полусвободное управление памятью. Если вы объявляете свойство как (retain), вам не нужно [newValue retain] самостоятельно. Синтезированный метод сделает это за вас (в обоих случаях вам все равно придется [ivar release] в вашем dealloc методе).

Вы также можете получить некоторую степень безопасности потока. Если вы не объявляете свойство как (nonatomic), тогда оно (по умолчанию) atomic (хотя это ключевое слово не существует; оно подразумевается). Это означает, что чтение / обновление значения свойства является атомарной операцией . Если бы вам нужно было просто получить доступ к ivar напрямую, вам бы пришлось самостоятельно реализовать атомарность с помощью замка.

По сути, использование синтезированных методов дает вам действительно полезные вещи бесплатно. Единственная причина, по которой я бы сказал не использовать синтаксис @property, заключается в том, что у вас есть неопровержимые доказательства того, что вызов этих методов является узким местом в вашем коде. Тем не менее, вам будет действительно трудно придумать ситуацию, в которой это будет иметь место.

1 голос
/ 17 февраля 2010

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

Ключевым отличием является то, что свойство фактически вызывает метод доступа, в то время как к переменной экземпляра обращаются напрямую.

Таким образом, для установки свойства retain использование self и метода доступа освободит старый объект и сохранит новый. Установка переменной экземпляра напрямую НЕ повлияет на количество сохраняемых объектов.

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

Основная причина использования свойств заключается в том, что, поскольку они являются средствами доступа, их можно читать и / или изменять извне класса.

...