Objective-C属性赋值返回赋值?

时间:2010-01-13 21:02:20

标签: objective-c gcc compiler-construction objective-c-runtime

说我有以下内容:

@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来收集返回值。但是,使用NSLog调用检测setter和getter方法证明情况并非如此。

4 个答案:

答案 0 :(得分:9)

快速摘要:

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

(mcInst.foobar = @"BAZ!")

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

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

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

使用此代码,foobar属性的值在设置时被修改,但您的代码行仍将显示值'BAZ!'。< / p>

<强>详细信息:

正如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中,然后使用参数42调用SomeFunction。在幕后,它看起来像这样:

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

现在,在Objective-C中,您的日志记录行按如下方式处理:

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

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

在C中,赋值是一个表达式,它的计算结果为赋值

答案 3 :(得分:0)

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

“赋值运算符将值存储在指定的对象中 左操作数。赋值表达式的值为left 任务后的操作数......“

您的作业表达式为mcInst.foobar = @"BAZ!"。对我来说似乎有意义,即使赋值通过调用mcInst上的方法,行为与C相同。赋值表达式的值是赋值后的左操作数(@"BAZ!")所以这个值传递给NSLog函数。

这与允许您以if (self = [super init])样式编写初始化程序的行为相同。

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