(不是这样)使用属性时愚蠢的Objective-C继承问题 - GCC Bug?

Ben*_*ard 13 inheritance cocoa gcc objective-c gcc4

更新 - 许多人坚持要我为该物业申报iVar.有些人说不是这样,因为我正在使用Modern Runtime(64位).我可以确认我已经成功使用@property而没有iVars几个月了.因此,我认为'正确'的答案是解释为什么在64位上我突然必须明确声明iVar何时(并且仅当)我将从子类访问它.到目前为止,我见过的唯一一个可能是GCC错误(感谢Yuji).毕竟不是那么简单......为了澄清可能的错误:当从基类继承时,子进程无法访问父进程的iVar,并且在访问iVar之前,该子进程也恰好使用@synthesize实现了一个UNRELATED访问器.

我一直在摸不着头几个小时 - 我没有太多使用遗产.

在这里,我设置了一个简单的Test B类,它继承自Test A,其中声明了一个ivar.但是我得到了变量未声明的编译错误.这只发生在我添加属性和合成声明时 - 没有它们就可以正常工作.

TestA标题:

#import <Cocoa/Cocoa.h>
@interface TestA : NSObject {
    NSString *testString;
}
@end
Run Code Online (Sandbox Code Playgroud)

TestA实现为空:

#import "TestA.h"
@implementation TestA  
@end
Run Code Online (Sandbox Code Playgroud)

TestB标题:

#import <Cocoa/Cocoa.h>
#import "TestA.h"
@interface TestB : TestA {
}
@property (nonatomic, retain) NSString *testProp;
@end
Run Code Online (Sandbox Code Playgroud)

TestB实现(错误 - 'testString'未声明)

#import "TestB.h"
@implementation TestB
@synthesize testProp;
- (void)testing{
    NSLog(@"test ivar is %@", testString);
}
@end
Run Code Online (Sandbox Code Playgroud)

Yuj*_*uji 10

我认为这是GCC 4.2.1的错误.我用foo.m内容制作了文件

#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
Run Code Online (Sandbox Code Playgroud)

请注意,在64位模式下可以省略实例变量.OS X 10.6.3上的我的GCC 4.2.1给了我一个错误:

$ 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.)
Run Code Online (Sandbox Code Playgroud)

通过更改编译没有问题

NSLog(@"test ivar is %@", testString);
Run Code Online (Sandbox Code Playgroud)

NSLog(@"test ivar is %@", self->testString);
Run Code Online (Sandbox Code Playgroud)

Clang编译它没有任何问题.

(在32位模式下,我得到了

$ 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.)
Run Code Online (Sandbox Code Playgroud)

正如Manjunath写的那样,这是一种完全预期的行为.)

但是我认为访问超类的实例变量通常是一个相当不错的主意:当你实现超类的方法时,你不能假设任何关于实例变量的东西,因为它可能会以最坏的方式被子类调整.您至少需要写下允许或不允许对实例变量执行何种操作...请记住,您可能需要多年维护代码!我更希望在方法和属性级别保持代码的各个部分之间的编程契约.

最后你应该改变

@property NSString *testProp;
Run Code Online (Sandbox Code Playgroud)

@property (copy) NSString *testProp;
Run Code Online (Sandbox Code Playgroud)

或至少到

@property (retain) NSString *testProp;
Run Code Online (Sandbox Code Playgroud)

如果您在OS X上没有使用GC,否则EXP_BAD_ACCESS将等待您的到来!