【发布时间】:2011-03-07 14:44:53
【问题描述】:
我遇到了一个奇怪的问题,涉及 Core Data、声明的协议,也许还有 LLVM 1.5 编译器。情况是这样的。
我有一个核心数据模型,其中有两个类,IPContainer 和 IPEvent,其中 IPContainer 是 IPEvent 的父实体。每个实体在项目中都有一个自定义类,使用 mogenerator 创建。 mogenerator 会生成一个仅包含建模属性声明的附加子类,因此类层次结构实际上是 IPEvent > _IPEvent > IPContainer > _IPContainer > NSManagedObject。 IPContainer 实体有一个名为“id”的属性,在_IPContainer.h 中声明为@property(nonatomic, retain) NSNumber* id;。 _IPContainer.m 在实现中有@dynamic id;,告诉Core Data 在运行时生成访问器
我的项目中还声明了一个协议 IPGridViewGroup,它定义了几个属性,其中一个是相同的“id”属性。但是,实现该协议的类不需要setter,因此协议中的属性声明为@property(readonly) NSNumber* id; IPEvent 类声明它符合IPGridViewGroup 协议。
使用 Clang/LLVM 1.0.x 编译器(无论 Xcode 3.2.2 附带的哪个版本)都可以正常工作,但是在升级到 Xcode 3.2.3 和 Clang/LLVM 1.5 后,一大堆事情发生了变化。首先,我在编译 IPEvent 类时收到以下警告:
/Volumes/Ratbert/Users/bwebster/Projects/UberProject/iPhotoLibraryManager/IPGridViewGroup.h:19:31: warning: property 'id' requires method 'id' to be defined - use @synthesize, @dynamic or provide a method implementation
然后,当我实际运行程序时,它会在控制台中打印出来:
Property 'id' is marked readonly on class 'IPEvent'. Cannot generate a setter method for it.
紧随其后的是:
-[IPEvent setId:]: unrecognized selector sent to instance 0x200483900
我还尝试在 IPEvent 类上重新声明该属性,但这只是给了我一个不同的编译器警告,以及在运行时的相同行为:
/Volumes/Ratbert/Users/bwebster/Projects/UberProject/iPhotoLibraryManager/IPManagedObject/IPEvent.h:14:40: warning: property 'id' 'retain' attribute does not match the property inherited from 'IPGridViewGroup'
现在,这里唯一改变的是编译器,所以改变的催化剂很清楚,但我不知道这是否可以被认为是新版本编译器中的错误,或者如果旧版本的编译器实际上表现不正确,而新版本现在显示这是我自己的代码有问题。
所以我的问题包括:
- 似乎应该可以让一个类符合具有只读属性的协议,但在其自己的实现中为该属性提供读写访问权限,对吗?不过这里的怪癖是 readwrite 属性实际上是在符合协议的类的超类中声明的。
- 我假设控制台消息正在Core Data 内部的某个地方打印出来。不过这很奇怪,因为 IPEvent 本身并没有明确声明“id”属性,除非符合 IPGridViewGroup 协议。但是,如果是这种情况,那么我认为会出现编译器 error,因为它会有效地使用相同属性的只读版本覆盖读写属性(在 _IPContainer 超类中声明) ,AFAIK 通常不允许允许。
- 如果这是一个编译器错误,那很好,我现在可以通过几种不同的方式解决它。如果编译器在这里做正确的事情,那么我将无法想出一种方法来组织所有这些,因此我不会收到任何编译器警告或运行时错误。
编辑: 所以,解决方法是再次在 IPEvent 类上重新声明该属性,但我仍然对为什么两个版本的编译器行为不同感到困惑。还不清楚协议上声明的属性应该如何与类上声明的属性进行交互。
如果我在覆盖读写属性的类(而不是协议)中声明只读属性,我会收到消息“警告:属性 'longitude' 的属性 'readonly' 限制从 '_IPEvent 继承的属性的属性 'readwrite' '”。似乎如果在协议中声明它具有相同的效果,编译器应该会出现类似的警告。
不过,直观地说,我认为由于 IPEvent 已经为该属性实现了必要的 getter,这应该算作“符合协议”,即使它碰巧也为该属性实现了一个 setter。
【问题讨论】:
标签: objective-c cocoa core-data llvm-clang