2

I can define a class with a property to access my ivars from outside of the class.

I can also just use the myInst->ivar syntax to access in a C-struct fashion.

In C++, I would go with accessors, but in objective-c there are some cases where I may want direct access. The messaging system incurs a large performance hit with the accessor that matters in some contexts, since the message isn't inlined like it can be with C++ methods.

For example in a class that has an ivar called scalar and a property defined on it. scalar is a simple float value:

-(void) doWorkWithMyClass:(MyClass*)myinst
{
   // array and other locals declaration omitted 
   for (int i = 0; i < reallyBigX; i++) {
      result += [myinst scalar] * array[i];
      [myinst computeNextScalar:i];
   }
}

If i change [myinst scalar] to myinst->scalar, the method will run a lot faster, since using calls with the accessor would take up most of the CPU in this loop.

As with C++ I understand direct ivar access is in general discouraged, but in this context, when speed matters, is it acceptable? If not, is there a more preferred method that still uses an objective-c class?

Michael Chinen
  • 17,737
  • 5
  • 33
  • 45
  • 1
    Usually you'd do the performance-intensive parts directly in C or C++. – Georg Fritzsche Feb 19 '12 at 23:44
  • 1
    How much of a performance hit are you seeing from using the accessor? Have you quantified the "large performance hit" and how much quicker it is to access the ivar directly, or is this pre-emptive postulation? – Aidan Steele Feb 20 '12 at 00:03
  • @GeorgFritzsche Yes, I normally do this, but this is a case that popped up when I wanted polymorphism, NSCoding, and ref counting within one class interface instead of splitting it up into structs/c++ classes and obj-c classes. – Michael Chinen Feb 20 '12 at 00:04
  • @SedateAlien The performance hit of the overal result of this envelope application is around 1.7 times slower. – Michael Chinen Feb 20 '12 at 00:10

2 Answers2

6

Many things become acceptable when it has a significant impact on performance, but in the example you're giving, there seem to be much better solutions.

First, why doesn't [myinst computeNextScalar:i] return the new scalar? If you did that, you wouldn't need to fetch it and everything would be much faster.

Can't the work be moved into myinst? I mean, can't you create something like:

result = [myinst totalOverArray:array];

If reallyBigX is really big, then you should consider the Accelerate.framework here. It can significantly improve performance on the kind of operation you seem to be doing. (You have to do performance testing with the Accelerate framework. It can be substantially slower for some operations, but this one might be faster.)

Finally, consider the Objective-C get... pattern. It looks like this:

int *scalars = calloc(reallyBigX, sizeof(int));
[myinst getScalars:scalars range:NSMakeRange(0, reallyBigX)];
for (int i = 0; i < reallyBigX; i++) {
   result += scalars[i] * array[i];
}
free(scalars);

BTW, the above is definitely a candidate for vDSP_dotpr(), though you should performance-test it. In many cases the simple loop is faster than an equivalent vDSP call when stride=1 (since you can use a simple increment rather than += stride).

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    These are all great sugestions, thanks. So, if you're going to use obj-c for this kind of thing, see if you can break up the messaging bottleneck into longer chunks as a first approach. The other optimization techniques sound interesting too. – Michael Chinen Feb 20 '12 at 01:05
  • "So, if you're going to use obj-c for this kind of thing, see if you can break up the messaging bottleneck into longer chunks as a first approach." -- Exactly. – Rob Napier Feb 20 '12 at 01:22
  • As I tried to use move the functionality into the array (totalOverArray) I realized this won't work for my case because the doWorkWithMyClass is polymorphed and behavior varies with each class. So I will go with the getScalars method. – Michael Chinen Feb 20 '12 at 02:17
1

Yes, it is acceptable: the @public, @private, etc. access modifiers were introduced in part to support designs where accessing ivars from outside the class is required. You should avoid writing directly to ivars, though.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523