Скажите, что у меня есть следующее:
@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!'
. К сожалению, это чувствует себя подобно противоречию, потому что возвращаемое значение вызванного метода set противоречит тому, что присвоение возвращает значение, присвоенное ему. Сначала я изобразил это mcInst.foobar = @"BAZ!";
выполняет два вызова вместо этого блок: сначала метод set и затем метод считывания для сбора возвращаемого значения. Однако оснащая методы установщика и методы получателя с NSLog
вызовы доказывают, что это не имеет место.
Быстрое обобщение:
Быстрый ответ здесь заключается в том, что противоречия нет, так как результатом выражения:
(mcInst.foobar = @"BAZ!")
на самом деле является @"BAZ!"
, а не mcInst.foobar
.
Более подробная информация доступна ниже, но, возможно, поможет рассмотреть следующую модификацию вашего метода setFoobar
:
- (void) setFoobar:(NSString*)fbSet
{
[_foobar release];
_foobar = [[NSString stringWithFormat:@"HELLO_%@", fbSet] retain];
}
При наличии этого кода, значение свойства foobar
изменяется во время его установки, , но в вашей строке кода все равно будет отображаться значение 'BAZ!'.
Подробности:
Как указывает newacct, ваш код NSLog работает, так как вы используете оператор присваивания (=), который имеет очень специфическое поведение в языке Си (на котором основана Objective-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);
(*) обратите внимание, что использование "временной переменной", которую я описываю, предназначено для иллюстрации концепции, и может на самом деле не отражать то, что любой данный компилятор на самом деле делает под капотом. Такая реализация зависит от программистов, которые пишут компилятор, и каждый из них может делать что-то свое. Конечный результат, однако, один и тот же.
в языке С, присвоение - это выражение, которое оценивает присвоенное значение
.Я нахожу плагин m2eclips e более полезным. Это обеспечивает хорошие инструменты, такие как редактор POM и создание проекта Maven в Eclipse.
-121--636036- Если точно известно, сколько вкладок префиксирует каждая строка (как указано), можно использовать простой query-replace-regex
для замены «^\t\t\t ...\t»
на «»
.
Это связано с путем работы оператора назначения C. Как описано в стандарте ANSI C:
"Оператор назначения сохраняет значение в объекте, обозначенном левый операнд. Выражение назначения имеет значение слева операнд после назначения "...
Выражение назначения mcInst.foobar = @" BAZ! "
. Мне кажется, имеет смысл, что даже если назначение работает путем вызова метода на mcInst поведение то же, что и с C. Значение выражения назначения является левым операндом после назначения ( @ «BAZ!»
), поэтому это значение передается функции NSLog.
Это то же поведение, которое позволяет написать инициализатор в стиле , если (self = [super init])
.
P.S. Справедливо задать вопрос, почему компилятор вызывает установщик свойства при присвоении ему значения и не вызывает получателя при последующем использовании значения mcInst.foobar
. Я бы сказал, что просто предполагается, что getter вернет то же значение, которое только что было присвоено свойству, и поэтому getter не называется.
Нет необходимости вызывать геттера - ему присваивается значение прямо на этой же линии. Можно считать, что оно расширяется до [mcInst setFoobar:@"BAZ!"], @"BAZ!"
.