Given the following property declaration:
@property NSInteger foo;
How do the increment, decrement, and compound assignment operators actually work on self.foo
?
It was my understanding that self.foo
was merely syntactic sugar for the actual accessor methods. So self.foo
isn't directly accessing an NSInteger
variable called foo
, but rather calling either:
- (void)setFoo:(NSInteger)foo;
or
- (NSInteger)foo;
Yet, the following set of code is perfectly fine, is not flagged, compiles fine, and returns exactly the expected results:
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
And I think it's probably safe to assume that the decrement pre and post fix operators as well as the other 9 compound operators will do exactly what you'd expect if you were using them directly on an NSInteger
variable.
I just don't understand WHY it works if self.foo
is truly just syntactic sugar for the two methods I mentioned above.
If I overwrite the default accessors to include NSLog
statements so I can see when each is called and with what values, I can see that the getter is called first then the setter is called.
Does this mean that the following:
self.foo += 1;
is effectively replaced with this:
[self setFoo:([self foo] + 1)];
during precompilation?
EDIT: So, at the assembly level, is there any difference between self.foo += 1;
and self.foo = self.foo + 1;
? What if we're not talking about a property, and bar
is just a regular int, at the assembly level is there a difference between bar += 1;
and bar = bar + 1;
?
Exactly. Your assumption is correct. You can implement property yourself and add logging to check your assumption one more time
In your @interface section:
@property(nonatomic) NSInteger foo;
// nonatomic keyword is not really required but
// it is better to add it since we will implement
// property as nonatomic
In @implementation section:
- (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;
}
Then run
self.foo = 0;
self.foo += 1;
you should receive in debug window:
set foo 0
get foo 0
set foo 1
UPDATE:
self.foo += 1;
and self.foo = self.foo + 1;
?"No. For both [self setFoo:([self foo] + 1)];
will be called.
bar += 1;
and bar = bar + 1;
?Yes. But only if compile time optimization is turned off.
bar += 1;
is faster. It will be compiled to something like:
mov eax,dword ptr [bar]
inc eax // difference is here!
mov dword ptr [bar],eax
And bar = bar + 1;
to:
mov eax,dword ptr [bar]
add eax,1 // difference is here!
mov dword ptr [bar],eax
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With