(Not So) Silly Objective-C inheritance problem when using property - GCC Bug?

六月ゝ 毕业季﹏ 提交于 2019-11-27 20:43:25

I think this is the bug of GCC 4.2.1. I made the file foo.m with the content

#import <Foundation/Foundation.h>
@interface TestA : NSObject {
    NSString *testString;
}
@end

@implementation TestA  
@end

@interface TestB : TestA {
}
@property (retain) NSString *testProp;
@end

@implementation TestB
@synthesize testProp;
- (void)testing{
NSLog(@"test ivar is %@", testString);
}
@end

Note that it's OK in the 64 bit mode to omit the instance variable. My GCC 4.2.1 on OS X 10.6.3 gave me an error:

$ gcc -arch x86_64 -c foo.m
aho.m: In function ‘-[TestB testing]’:
aho.m:19: error: ‘testString’ undeclared (first use in this function)
aho.m:19: error: (Each undeclared identifier is reported only once
aho.m:19: error: for each function it appears in.)

This compiled without problem by changing

NSLog(@"test ivar is %@", testString);

to

NSLog(@"test ivar is %@", self->testString);

Clang compiled it without any problem.

( In the 32 bit mode, I got

$ gcc -arch i386 -c foo.m
aho.m:17: error: synthesized property ‘testProp’ must either be named 
the same as a compatible ivar or must explicitly name an ivar
aho.m: In function ‘-[TestB testing]’:
aho.m:19: error: ‘testString’ undeclared (first use in this function)
aho.m:19: error: (Each undeclared identifier is reported only once
aho.m:19: error: for each function it appears in.)

which is a perfectly expected behavior, as Manjunath wrote.)

However I think it's generally a rather bad idea to access an instance variable of the superclass: when you implement the methods the superclass, you cannot assume anything about the instance variable because it might be tweaked in a worst manner possible by the subclass. You at least need to write down what kind of operation on the instance variable is permitted or not... Remember you might need to maintain your code for years! I would prefer keeping programming contracts between various parts of the code at the level of methods and properties.

Finally you should change

@property NSString *testProp;

to

@property (copy) NSString *testProp;

or at least to

@property (retain) NSString *testProp;

if you're not using GC on OS X. Otherwise EXP_BAD_ACCESS will await you!

I think you just have a typo - it should be "testString" not "test"

I'm seeing error: 'testString' undeclared (first use in this function) when the @synthesize is just before the testing method. The error disappears if I move the @synthesize below the method implementation. This might be because the TestB class doesn't have a testProp string instance variable to use with the declared property. (In the Legacy (32-bit) runtime, you must declare instance variables to use for properties — in Modern runtime (64-bit Mac, iPhone) they can be inferred, so declaring them is optional.) Is it possible that you meant to name the property testString instead?


EDIT: In GCC 4.2, it works if you change TestB.h to the following:

#import "TestA.h"

@interface TestB : TestA {
    NSString *testProp; // <-- Adding this fixes the errors
}
@property NSString *testProp;

@end

However, using the Clang-LLVM compiler, the code works unmodified. Perhaps this is a bug to file.

I just ran into that same problem but the sources were complex enough that I didn't quite understand what made iVar from the parent inaccessible when I used GCC. I only knew for sure that a few months ago and before changes in my code it worked and also that it is working with clang which I've been using for a while. Suddenly I had to build with GCC and it wouldn't anymore.

At least this article gave me a bypass (declare the iVars). I am surprised that the latest version of XCode does not include a fixed compiler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!