为啥不声明实例变量?

Posted

技术标签:

【中文标题】为啥不声明实例变量?【英文标题】:Why isn't the instance variable declared?为什么不声明实例变量? 【发布时间】:2013-01-15 19:39:46 【问题描述】:

我使用的是 xcode 4.5.2 和 LLVM 4.1。我期望我不需要合成类属性也不需要声明实例变量,但我收到的错误表明这些期望是错误的。

我的班级:

@interface Test : NSManagedObject
@property (strong, nonatomic) NSString *string;
@property (strong, nonatomic) NSString *number;
@end

@implementation Test
- (NSString*)string 
    return _string;

@end

1) 使用未声明的标识符“字符串”

我还在 WWDC 2010 Session 144 中看到了以下内容:

return self->string;

但这会导致建议使用点表示法时出错。

2) 在“Test *”类型的对象上找到属性“string”;你的意思是用“。”访问它吗?运营商?

我也收到了number 的警告:

3) 属性 'number' 需要定义方法 'number' - 使用 @synthesize、@dynamic 或在此类实现中提供方法实现

我完全不知道这里发生了什么。它开始让我的血液有点沸腾。我错过了什么?

【问题讨论】:

您上面的示例代码应该可以工作。我正在使用 Xcode 4.5.2 和 LLVM 4.1 尝试您的示例。它对我来说很干净。这里没有构建问题。 另外,我在很多场合都有意使用了您的示例代码所显示的技术。据我了解,这是 LLVM 后期版本支持的行为。 啊!由于您是 NSManagedObject 的子类,我想说这会使事情变得非常复杂。在这种情况下,我会严格坚持使用self.foo[self valueForKey:@"foo"] 表示法访问属性。考虑到我认为 Apple 不会对它如何在托管对象中声明其 ivars 做出任何保证,这会更安全。 我很确定 Apple 建议您不要覆盖 NSManagedObject 子类中的属性访问器和设置器。这就是 CoreData 的魅力所在。我认为覆盖这些会自找麻烦。 关于“托管对象访问器方法”的 Apple 文档:developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/… 【参考方案1】:

首先,点符号是你的朋友!

其次,当您尝试使用-> 时,您必须访问ivar。在最新版本的 Xcode 和 LLVM 中,如果您没有使用 @synthesize 自己指定一个,则会为您创建一个带下划线的 ivar。

所以你会做self->_string。当您使用推荐的. 时,您可以访问该属性。这也可能是您在number 上收到警告的原因,因为self->number 不存在。


编辑:针对您使用NSManagedObject 的事实,我绝对推荐使用属性(如托德推荐的)。 NSManagedObjects 希望你使用 @dynamic,因为 Core Data 在后台做了很多事情,Apple 建议你不要改变它。

如果您想要自定义 getter/setter,我会使用 another SO question,它使用 primitive 方法:

- (NSString *)name

    [self willAccessValueForKey:@"name"];
    NSString *myName = [self primitiveName];
    [self didAccessValueForKey:@"name"];
    return myName;

当然还有Apple Docs on the matter。还有一个与 ios 6 相关的 related question/solution。

【讨论】:

除了 .建议使用运算符,因为它们不同,可能会在您需要使用 -> 运算符时发生。此外,他的代码应该可以编译。 请注意,尽管在访问器方法中使用点符号会导致无限循环。另外,当我执行self->_string 时,它说'Test' 没有名为'_string' 的成员。所以这里出了点问题。 查看我对我的问题的评论。似乎语法确实有效,但在我的情况下不是我扩展另一个类的方式。试图找出导致问题的原因。 我会接受您的回答,因为它现在解决了问题的真正原因。请添加此 SO 问题作为对该问题的参考:***.com/a/12544653/143225 MishieMoo,它解释了为什么NSManagedObjectNSObject 在自动合成属性方面不同。【参考方案2】:

如果您同时为属性实现了 setter 和 getter 方法,那么编译器会假定您也在处理后备存储,并且不会为您创建 _string 实例变量。

您可以自己手动声明,也可以使用@synthesize string = _string; 强制编译器为您声明。后者将根据属性类型为 ivar 提供正确的内存管理语义(强、弱等)。

对于托管对象,您需要实现 MishieMoo 的答案,但这是您的 NSObject 子类没有问题中所述的 _string 变量的原因。

详细介绍here

【讨论】:

我的测试对象实际上是一个NSManagedObject,我已经编辑了我的问题以反映这一点,因为它是我问题的根源。不过,感谢您提供更多信息。

以上是关于为啥不声明实例变量?的主要内容,如果未能解决你的问题,请参考以下文章

为啥实例变量在java中有默认值? [复制]

为啥我的实例变量在我的 Rails 视图中总是 Nil

为啥 C# 公共静态变量不需要实例化?

为啥可以在java的抽象类中声明瞬态变量? [复制]

java:在java中为啥静态变量没有this引用?

在 C++ 中声明实例变量而不构造它们的好方法是啥? [关闭]