ObjC属性和C运算符

nhg*_*rif 7 properties objective-c increment operators compound-assignment

鉴于以下财产声明:

@property NSInteger foo;
Run Code Online (Sandbox Code Playgroud)

增量,减量和复合赋值运算符如何实际工作self.foo

我的理解self.foo仅仅是实际存取方法的语法糖.所以self.foo不是直接访问一个NSIntegerfoo调用的变量,而是调用它们:

- (void)setFoo:(NSInteger)foo;
Run Code Online (Sandbox Code Playgroud)

要么

- (NSInteger)foo;
Run Code Online (Sandbox Code Playgroud)

然而,下面的一组代码完全没问题,没有标记,编译得很好,并且完全返回预期的结果:

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
Run Code Online (Sandbox Code Playgroud)

而且我认为假设前后修复操作符以及其他9个复合操作符的递减将完全符合您在NSInteger变量上直接使用它们时的预期,这可能是安全的.

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

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

这是否意味着以下内容:

self.foo += 1;
Run Code Online (Sandbox Code Playgroud)

被有效地替换为:

[self setFoo:([self foo] + 1)];
Run Code Online (Sandbox Code Playgroud)

在预编译期间?


编辑:那么,在汇编级别,self.foo += 1;和之间有什么区别self.foo = self.foo + 1;?如果我们不是在谈论一个属性,并且bar只是一个常规的int,在汇编级别,那么bar += 1;和之间有什么区别bar = bar + 1;呢?

Avt*_*Avt 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
Run Code Online (Sandbox Code Playgroud)

在@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;
}
Run Code Online (Sandbox Code Playgroud)

然后跑

self.foo = 0;
self.foo += 1;
Run Code Online (Sandbox Code Playgroud)

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

set foo 0
get foo 0
set foo 1
Run Code Online (Sandbox Code Playgroud)

更新:

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

[self setFoo:([self foo] + 1)];不会.两者都会被召集.

  • 回复:我们不是在谈论什么,如果有关的属性,和酒吧只是一个普通的INT,在组件级别是有之间的差异bar += 1;bar = bar + 1;

是.但只有关闭编译时优化.

bar += 1;是比较快的.它将被编译为类似于:

mov eax,dword ptr [bar]
inc eax                // difference is here!
mov dword ptr [bar],eax
Run Code Online (Sandbox Code Playgroud)

bar = bar + 1;:

mov eax,dword ptr [bar]
add eax,1              // difference is here!
mov dword ptr [bar],eax
Run Code Online (Sandbox Code Playgroud)