为啥不声明实例变量?
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,它解释了为什么NSManagedObject
与NSObject
在自动合成属性方面不同。【参考方案2】:
如果您同时为属性实现了 setter 和 getter 方法,那么编译器会假定您也在处理后备存储,并且不会为您创建 _string
实例变量。
您可以自己手动声明,也可以使用@synthesize string = _string;
强制编译器为您声明。后者将根据属性类型为 ivar 提供正确的内存管理语义(强、弱等)。
对于托管对象,您需要实现 MishieMoo 的答案,但这是您的 NSObject 子类没有问题中所述的 _string 变量的原因。
详细介绍here
【讨论】:
我的测试对象实际上是一个NSManagedObject
,我已经编辑了我的问题以反映这一点,因为它是我问题的根源。不过,感谢您提供更多信息。以上是关于为啥不声明实例变量?的主要内容,如果未能解决你的问题,请参考以下文章