7

给定以下属性声明:

@property NSInteger foo;

递增、递减和复合赋值运算符实际上是如何工作的self.foo

据我了解,这self.foo只是实际访问器方法的语法糖。所以self.foo不是直接访问一个NSInteger名为 的变量foo,而是调用任何一个:

- (void)setFoo:(NSInteger)foo;

或者

- (NSInteger)foo;

然而,以下代码集非常好,没有标记,编译正常,并且完全返回了预期的结果:

self.foo = 0;
NSLog(@"%d",self.foo); // prints 0

self.foo += 1;
NSLog(@"%d",self.foo); // prints 1

self.foo++;
NSLog(@"%d",self.foo); // prints 2

++self.foo;
NSLog(@"%d",self.foo); // prints 3

而且我认为可以安全地假设递减 pre 和 post fix 运算符以及其他 9 个复合运算符将完全按照您在NSInteger变量上使用它们时的预期效果。

我只是不明白为什么它self.foo真的只是我上面提到的两种方法的语法糖。

如果我覆盖默认访问器以包含NSLog语句,以便我可以看到每个访问器何时被调用以及使用什么值,我可以看到首先调用 getter,然后调用 setter。

这是否意味着以下内容:

self.foo += 1;

被有效地替换为:

[self setFoo:([self foo] + 1)];

在预编译期间?


编辑:self.foo += 1;那么,在装配层面,和之间有什么区别self.foo = self.foo + 1;吗?如果我们不是在谈论一个属性,而只是一个普通的 int,那么在汇编级别,和bar之间有区别吗?bar += 1;bar = bar + 1;

4

1 回答 1

6

确切地。你的假设是正确的。您可以自己实现属性并添加日志记录以再次检查您的假设

在您的@interface 部分:

@property(nonatomic) NSInteger foo; 
     // nonatomic keyword is not really required but 
     // it is better to add it since we will implement 
     // property as nonatomic

在@implementation 部分:

- (void)setFoo:(NSInteger)foo
{
    _foo = foo; // _foo variable is implicitly generated by compiler
    NSLog(@"set foo %d", _foo);
}

- (NSInteger)foo
{
    NSLog(@"get foo %d", _foo);
    return _foo;
}

然后运行

self.foo = 0;
self.foo += 1;

您应该在调试窗口中收到:

set foo 0
get foo 0
set foo 1

更新:

  • self.foo += 1;回复:“在装配级别,和之间有什么区别self.foo = self.foo + 1;吗?”

不,因为两者[self setFoo:([self foo] + 1)];都会被调用。

  • 回复:如果我们不是在谈论属性怎么办,而 bar 只是一个常规的 int,在汇编级别,bar += 1;和之间有区别bar = bar + 1;吗?

是的。但只有在编译时优化关闭的情况下。

bar += 1;是比较快的。它将被编译为:

mov eax,dword ptr [bar]
inc eax                // difference is here!
mov dword ptr [bar],eax

bar = bar + 1;

mov eax,dword ptr [bar]
add eax,1              // difference is here!
mov dword ptr [bar],eax
于 2014-05-01T22:33:07.523 回答