Objective-C 属性赋值返回指定的值?

问题描述 投票:0回答:4

假设我有以下内容:

@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 方法证明情况并非如此。

objective-c gcc objective-c-runtime
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;

所有变量

x
y
z
将保持值 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);

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


1
投票

无需调用 getter — 它的值就在同一行上分配。您可以将其视为扩展到

[mcInst setFoobar:@"BAZ!"], @"BAZ!"


0
投票

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


0
投票

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

“赋值运算符将值存储在由 左操作数。 赋值表达式的左侧值为 赋值后的操作数...”

您的赋值表达式是

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

这与允许您以

if (self = [super init])
的风格编写初始化程序的行为相同。

附注一个合理的问题是,为什么编译器在给属性赋值时会调用该属性的 setter,而在之后使用

mcInst.foobar
的值时不调用 getter。我想说的是,它只是假设 getter 将返回刚刚分配给属性的相同值,因此不会调用 getter。

© www.soinside.com 2019 - 2024. All rights reserved.