6

说我有以下内容:

@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!'. 不幸的是,这感觉像是一个矛盾,因为调用的 setter 的返回值掩盖了赋值返回分配给它的值的事实。起初我认为这mcInst.foobar = @"BAZ!";是进行两次调用而不是一个块:首先是 setter,然后是 getter 以收集返回值。但是,使用调用来检测 setter 和 getter 方法NSLog证明情况并非如此。

4

4 回答 4

9

快速总结:

这里的快速回答是没有矛盾,因为表达式的结果:

(mcInst.foobar = @"BAZ!")

实际上是@"BAZ!",而不是 mcInst.foobar

下面提供了更多详细信息,但考虑对您的setFoobar方法进行以下修改可能会有所帮助:

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

使用此代码,foobar属性的值在设置时会被修改,但您的代码行仍将显示值“BAZ!” .

细节:

正如newacct所指出的,您的 NSLog 代码之所以有效,是因为您使用了赋值运算符 (=),它在 C 语言中具有一些非常具体的行为(Objective-C 基于此)

在 C 中,您可以执行以下操作:

x = y = z = 42;

并且所有变量 ,xyz保持值 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);

(*) 请注意,我描述的“临时变量”的使用是为了说明这个概念,可能实际上并不能真正反映任何给定编译器实际上在幕后所做的事情。这种实现细节取决于编写编译器的程序员,每个人都可能做不同的事情。然而,最终的结果是一样的。

于 2010-01-13T21:54:47.083 回答
1

没有必要调用 getter——它的值在同一行被分配。您可以将其视为扩展至[mcInst setFoobar:@"BAZ!"], @"BAZ!".

于 2010-01-13T23:40:35.543 回答
0

在 C 中,assignment 是一个表达式,其计算结果为分配的值

于 2010-01-13T21:18:10.850 回答
0

这是因为 C 赋值运算符的工作方式。如 ANSI C 标准中所述:

“赋值运算符将值存储在左操作数指定的对象中。赋值表达式具有赋值后左操作数的值......”

你的赋值表达式是mcInst.foobar = @"BAZ!". 对我来说似乎很有意义,即使通过调用 mcInst 上的方法进行赋值,其行为与 C 相同。赋值表达式的值是赋值 ( @"BAZ!") 之后的左操作数,因此该值被传递给 NSLog功能。

这与允许您以if (self = [super init]).

PS这是一个公平的问题,问为什么编译器在为它分配值时会调用属性的setter,而不是在使用mcInst.foobar之后的值时调用getter。我想说的是,它只是假设 getter 将返回刚刚分配给属性的相同值,因此不会调用 getter。

于 2010-01-13T23:30:56.917 回答