I'm going to invoke @bbum again hoping that he'll get the message and come and correct this answer.... But I'll do my best here.
In the old ABI, you could not hide your ivars. The compiler will catch the kinds of conflicts you're discussing in any case where they would matter. That said, I've found it's probably better to just avoid the problem by using some other naming convention. This way, when you find that there is already a _data
in your superclass (as I have), you don't have to come up with some other random name, or accidentally access the superclass's private data when you didn't mean to. Despite my original dislike, Google's trailing underscore has grown on me since I used it in a large project.
The reason you couldn't hide your ivars (and if you did somehow, you wouldn't get name collisions anyway) is that ivars used to be just struct offsets. Hampster Emporium has a nice short post explaining this. At runtime, there is no _window
, there is only offset 20. (Again, this is the old ABI I'm talking about).
This is not true for methods. They can collide. This is a bad thing when it happens. You don't get a warning. It really annoys me that Apple has private methods that do not have leading underscores on them. I have collided with them and the behavior is undefined. They reserved underscore; they should use it. (NSMutableArray
had a private -pop
method in a category that was implemented backwards of how I implemented my category with the same name. The resulting bugs in UINavigationController
were entertaining to say the least.)
That digression to the side, with the new ABI, it is now possible to have "hidden" ivars. You just declare them as synthesized properties in a private class extension. But through the magic of the new ABI (ok, not magic, just pointers), the ivars are safe even if they collide. But the synthesized methods aren't safe from collision. Note how directly accessing the ivar below gives you the expected behavior, but using the property gives a surprising result. I haven't worked out how a developer should best avoid or even detect this kind of situation.
EDIT Based on my discussion with @Bavarious, I moved this code to the version of clang that comes with Xcode 4 (most of my boxes are still on Xcode 3). It complains with all the kinds of loud errors you'd hope for. Particularly you get "Property someIvar
is already implemented." So that bodes very well for using @property
the way you'd want to.
#import <Foundation/Foundation.h>
// SomeClass.h
@interface SomeClass : NSObject
@end
// SomeClass.m
@interface SomeClass ()
@property (copy) NSString *someIvar;
@end
@implementation SomeClass
@synthesize someIvar;
- (id)init {
self = [super init];
if (self) someIvar = @"SomeClass";
return self;
}
- (void)print
{
NSLog(@"Superclass=%@:%@", someIvar, [self someIvar]);
}
@end
// SubClass.h
@interface SubClass : SomeClass
{
NSString *someIvar;
}
@property (copy) NSString *someIvar;
@end
// SubClass.m
@implementation SubClass
@synthesize someIvar;
- (id)init {
self = [super init];
if (self) someIvar = @"SubClass";
return self;
}
- (void)print
{
[super print];
NSLog(@"Subclass=%@:%@", someIvar, [self someIvar]);
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
SubClass *subclass = [[SubClass alloc] init];
[subclass print];
[pool drain];
return 0;
}
Superclass=SomeClass:SubClass <== Note the mismatch
Subclass=SubClass:SubClass