Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ObjC properties and C operators

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;?

like image 891
nhgrif Avatar asked May 01 '14 21:05

nhgrif


1 Answers

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:

  • Re: "at the assembly level, is there any difference between self.foo += 1; and self.foo = self.foo + 1;?"

No. For both [self setFoo:([self foo] + 1)]; will be called.

  • Re: 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;?

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
like image 117
Avt Avatar answered Nov 19 '22 16:11

Avt