views:

322

answers:

2

what's the difference between a C function (static or not) declared inside or outside the implementation block (@implementation ... @end) of a Objective-C class?

is this specially true?:

If you need to poke inside of the object directly, you can put this function inside of the @implementation block of your class, and then you can access instance variables with the C arrow operator. But that’s kind of naughty, so to preserve your Purity of Essence you should be using method calls on your object. End of Sermon. Here’s the evil:

@implementation OblateSphereoid

void drawEggThunk (DrawingContext *context, Rect areaToDraw, void *userData)
{
BWOblateSphereoid *dealie = (BWOblateSphereoid *)userData;
dealie->_frognatz = [NSColor plaidColor];
// and more stuff.
} // drawEggThunk

...
@end // OblateSphereoid

can i access instance variables of my class within functions (declared in the same class) in this way?

+1  A: 

This will work fine if its inside your @implementation. I'd recommend you make it a normal method, but it works.

If you put it out of your implementation, you get this warning: Warning: instance variable '' is @protected; this will be a hard error in the future. You can avoid this error by putting a @public before your iVar in the header... like so:

@public int myInt;

That allows you to access the variables like a C (pointer) Struct wherever the object appears without warning.

So its doable, not recommended though!!!

micmoo
i think this may be a bad practice too, but i don't want to expose the ivar as public just in favor of encapsulation, but my C callback functions must be capable of see the instance ivars.
jlpiedrahita
Then you should do what you have to do... you don't have to declare all your iVars as public, you can mix and match.
micmoo
+1  A: 

While this is legal, I don't understand why it's required in the kind of case you've described (and it is an ugly solution). Why can't you just call:

[dealie setFrognatz:[NSColor plaidColor]];

If you don't usually provide a -setFrognatz:, just make it a private method by declaring it inside the .m, but above this function definition. (It doesn't actually matter if it's in the @implementation block in this case.)

@interface BWOblateSphereoid ()
- (void)setFrognatz:(NSColor *)acolor
@end

@implementation OblateSphereoid

void drawEggThunk (DrawingContext *context, Rect areaToDraw, void *userData)
{
    BWOblateSphereoid *dealie = (BWOblateSphereoid *)userData;
    [dealie setFrognatz:[NSColor plaidColor]];
    // and more stuff.
} // drawEggThunk

...
@end // OblateSphereoid

There are a few places where -> notation can be helpful. The most critical is in implementing -copyWithZone: where it can be absolutely required (a requirement that really emphasizes why I hate any ObjC code that plays with raw memory like NSCopyObject() does). But I recommend against -> in most cases for the same reasons I always recommend accessors. Even in the case where you need to pass an ivar by reference to a C function (another common use of ->), I prefer using a temporary and then assigning it afterwards.

I consider the fact that ivars are not @private by default to be a bug in ObjC.... I put @private at the top of every @interface block and have avoided several nasty bugs that way.

BTW, your solution as written may be leaking an NSColor. Maybe it is, maybe it's not, but an accessor would be certain.

Rob Napier
The "private" method is the answer for the underlying problem (access ivars within functions without break encapsulation) :) but ... there's some difference between functions inside and outside @impementation?
jlpiedrahita
by the way, objc ivars are by default @protected, this is the perfect scope: visible for the class itself and subclasses, and hidden for all the rest.
jlpiedrahita
There's no difference between inside and outside @implementation.
Rob Napier
I disagree that subclasses should be able to see the ivars of their superclass. They should be using accessors (and ObjC needs @protected on methods so we could implement that more easily). Access to your superclass's ivars leads to a nasty bug opportunity (which I've had burn me). You hoist a superclass but forget to remove the ivar releases from the subclass dealloc. When you dealloc, you and your superclass release the ivar and you crash. @private catches that at compile time. You should always use accessors for everything, so there's little good reason to access your superclass's ivars.
Rob Napier