Назначение свойства Objective-C возвращает назначенное значение? - PullRequest
6 голосов
/ 14 января 2010

Скажите, у меня есть следующее:

@interface MyClass : NSObject { NSString* _foobar; }
@property (nonatomic, retain) NSString* foobar;
@end

@implementation MyClass
@dynamic foobar;
- (void) setFoobar:(NSString*)fbSet; { [_foobar release]; _foobar = [fbSet retain]; }
- (NSString*) foobar; { return _foobar; }
@end

Тогда:

MyClass* mcInst = [[[MyClass alloc] init] autorelease];
NSLog(@"I set 'foobar' to '%@'", (mcInst.foobar = @"BAZ!"));

Глядя на возвращаемое значение -[MyClass setFoobar:], здесь можно предположить, что эта строка напечатает I set 'foobar' to '', потому что назначение, похоже, ничего не возвращает.

Однако, к счастью, это назначение действует как ожидалось, и код печатает I set 'foobar' to 'BAZ!'. К сожалению, это похоже на противоречие, потому что возвращаемое значение вызванного установщика противоречит тому факту, что присвоение возвращает присвоенное ему значение. Сначала я подумал, что mcInst.foobar = @"BAZ!"; делает два вызова вместо блока: сначала установщик, а затем получатель, чтобы собрать возвращаемое значение. Однако инструментарий методов установки и получения с помощью вызовов NSLog доказывает, что это не так.

Ответы [ 4 ]

9 голосов
/ 14 января 2010

Краткое резюме:

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

(mcInst.foobar = @"BAZ!")

на самом деле @"BAZ!"и not mcInst.foobar.

Более подробная информация доступна ниже, но может помочь рассмотреть следующую модификацию вашего setFoobar метода:

- (void) setFoobar:(NSString*)fbSet
{
    [_foobar release];
    _foobar = [[NSString stringWithFormat:@"HELLO_%@", fbSet] retain];
}

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

Подробности:

Как указано newacct , ваш код NSLog работает, потому что вы используете оператор присваивания (=), который имеет очень специфическое поведение в языке Си (на чем основан Objective-C)

В C вы можете сделать следующее:

x = y = z = 42;

и все переменные x, y и z будутудерживайте значение 42.

Компилятор обрабатывает это поведение с помощью временной переменной (*).По сути, то, что происходит за кулисами, выглядит примерно так:

tempVar = 42;
z = tempVar;
y = tempVar;
x = tempVar;

В том же ключе вы можете сделать следующее:

SomeFunction(x = 42);

эта строка кода скопирует значение42 в x, а затем вызовите SomeFunction с аргументом 42. За кулисами это выглядит так:

tempVar = 42;
x = tempVar;
SomeFunction(tempVar);

Теперь в Objective-C ваша строка регистрации обрабатывается следующим образом:

tempVar = @"BAZ!";
[mcInst setFooBar:tempVar];
NSLog(@"I set 'foobar' to '%@'", tempVar);

(*) обратите внимание, что использование «временной переменной», которую я описываю, предназначено для иллюстрации концепции и может не отражать того, что на самом деле делает любой данный компилятор.Такой тип реализации зависит от программистов, которые пишут компилятор, и каждый может делать что-то свое.Однако конечный результат тот же.

1 голос
/ 14 января 2010

Нет необходимости вызывать геттер - он имеет значение, назначаемое прямо на той же строке. Вы можете думать об этом как о расширении до [mcInst setFoobar:@"BAZ!"], @"BAZ!".

0 голосов
/ 14 января 2010

Это из-за того, как работает оператор присваивания C. Как описано в стандарте ANSI C:

"Оператор присваивания сохраняет значение в объекте, обозначенном левый операнд. Выражение присваивания имеет значение слева операнд после присваивания ... "

Ваше выражение присваивания mcInst.foobar = @"BAZ!". Мне кажется, имеет смысл, что, хотя назначение работает, вызывая метод в mcInst, поведение аналогично C. Значение выражения присваивания является левым операндом после присваивания (@"BAZ!"), поэтому это значение передается в функцию NSLog.

Это то же поведение, которое позволяет вам написать инициализатор в стиле if (self = [super init]).

P.S. Справедливо задать вопрос, почему компилятор вызывает метод установки для свойства при назначении ему значения и не вызывает метод получения при использовании значения mcInst.foobar впоследствии. Я бы сказал, что просто предполагается, что получатель вернет то же значение, которое было только что присвоено свойству, и поэтому получатель не вызывается.

0 голосов
/ 14 января 2010

в C, присваивание является выражением, которое оценивается как присвоенное значение

...