开发者

If a subclass refers to a superclass ivar, synthesizing an unrelated property fails

Edit: I just noticed this other Stack Overflow question asking much the same thing: Why does a subclass @property with no corresponding ivar hide superclass ivars?

This is some interesting behavior that I cannot find documented in anything official or unofficial (blog, tweet, SO question, etc). I have boiled it down to its essence and tested this in a fresh Xcode project, but I can't explain it.

MyBaseClass has an instance variable:

@interface MyBaseClass : NSObject {
    NSObject *fooInstanceVar;
}
@end

MySubclass extends MyBaseClass, and declares a totally unrelated property (that is, the property is not intended to be backed by the instance variable):

#import "MyBaseClass.h"
@interface MySubclass : MyBaseClass { }
@property (nonatomic, retain) NSObject *barProperty;
@end

If the implementation of MySubclass does not synthesize the property but implements the accessor methods, everything is fine (no compiler error):

#import "MySubclass.h"
@implementation MySubclass

- (NSObject*)barProperty {
    return [[NSObject alloc] init]; // pls ignore flagrant violation of memory rules.
}

- (void)setBarProperty:(NSObject *)obj { /* no-op */ }

- (void)doSomethingWithProperty {
    NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil];
    NSLog(@"%@", array);
}
@end

But if I remove the property accessor methods and replace them with a synthesize开发者_运维技巧 declaration for the property, I get a compiler error: 'fooInstanceVar' undeclared (first use in this function).

#import "MySubclass.h"
@implementation MySubclass
@synthesize barProperty;

- (void)doSomethingWithProperty {
    NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil];
    NSLog(@"%@", array);
}
@end

This error goes away if I remove either the synthesize declaration, or if I do not refer to the fooInstanceVar instance variable from within MySubclass.m, or if I put all interface and implementation definitions in a single file. This error also seems to happen in both GCC 4.2 and GCC/LLVM build settings.

Can anyone explain what's happening here?


As replied in this question : objective c xcode 4.0.2: subclass can't access superclass variables "was not declared in this scope"

From the doc : Apple Objective-C Programming Langage : http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF125

The instance variable is accessible within the class that declares it and within classes that inherit it. All instance variables without an explicit scope directive have @protected scope.

However, a public instance variable can be accessed anywhere as if it were a field in a C structure. For example:

Worker *ceo = [[Worker alloc] init];

ceo->boss = nil;

I have the compilation error using LLVM GCC 4.2 (for an iOS project, on device) :

error: 'fooInstanceVar' undeclared (first use in this function) and the same one using GCC 4.2 : error: 'fooInstanceVar' undeclared (first use in this function)

I can compile using LLVM Compiler 2.0 whithout error.

For compiling with LLVM GCC 4.2 and GCC 4.2 with the use of self-> :

[NSArray arrayWithObjects:self.barProperty, self->fooInstanceVar, nil]; in the doSomethingWithProperty method.


The compiler is behaving correctly; synthesis in a subclasss using storage in a superclass is verboten.

There was a bug about this filed against llvm at some point. It may be in the publicly accessible bug database.

In any case, please file a bug asking for clarification of this particular rule.


I just tried this and it compiles without warning. What am I not doing?

@interface MyBaseClass : NSObject {
    NSObject *fooInstanceVar;
}
@end

@interface MySubclass : MyBaseClass { }
@property (nonatomic, retain) NSObject *barProperty;
@end

@implementation MyBaseClass
@end

@implementation MySubclass
@synthesize barProperty;

- (void)doSomethingWithProperty {
    NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil];
    NSLog(@"%@", array);
}
@end

It isn't clear what problem you are trying to solve. All instance variables are non-fragile everywhere but 32 bit Mac OS X.


I can't reproduce your error either. Do you have a non-default compiler flag set? Could you provide a copy of your project? It definitely appears to be a bug in the compiler.

Check out this article here for the best use of @property/@synthesize. A quick summary is to remove all of your ivars from your objects (unless you need to use the 32-bit runtime for some reason). Then only use your getters and setters, rather than accessing the synthesized ivars directly. Following this will avoid any future problems with this bug.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜