如果错误消息引用核心数据文件,请阅读此答案
概要:您可能同时拥有自动生成和手动生成的 Core Data 托管对象类文件。
如果错误的第一行涉及Foo+CoreDataProperties.o或Foo+CoreDataClass.o文件,则此答案适用。例子:
error: Multiple commands produce '/Users/me/Library/Developer/Xcode/DerivedData/MyApp-uebslaqdwgldkjemijpdqmizgyzc/Build/Intermediates.noindex/ MyApp /Debug-iphonesimulator/ MyApp.build/Objects-normal/x86_64/Foo+CoreDataProperties.o':
1) Target ' MyApp ' (project ' MyApp ') has compile command for Swift source files
2) Target ' MyApp ' (project ' MyApp ') has compile command for Swift source files
可以通过展开 Build Transcript 的Compile Swift Source Files部分来查看根本原因。例如:
<unknown>:0: error: filename "Address+CoreDataClass.swift" used twice: '/Users/myUserName/Projects/Jnky/Foo+CoreDataProperties' and '/Users/jk/myUserName/Developer/Xcode/DerivedData/MyApp-uebslaqdwgldkjemijpdqmizgyzc/Build/Intermediates.noindex/MyApp.build/Debug/MyApp.build/DerivedSources/CoreDataGenerated/Jnky/Foo+CoreDataProperties.swift'
提到的第一个文件在您的项目目录中有一个源文件,有人通过在 Project Navigator 中选择您的数据模型并单击菜单Editor > Create Managed Object Subclass来生成该文件。这个特性是在 Xcode 7 左右添加的。
第二个文件是一个同名文件,但它隐藏在 Xcode 的DerivedData
. 如果数据模型 ( ) 文件包含在目标的编译源构建阶段,则 Xcode 在每次构建期间自动生成此文件。这个特性是在 Xcode 9 左右添加的。根据Codegen弹出窗口的设置,为每个实体/类生成零个、一个或两个文件。当您在编辑数据模型时选择实体时,
该弹出窗口位于数据模型检查器中……</p>.xcdatamodeld

设置如下:
- 手动/无不生成文件
- 类别/扩展生成一个文件Foo+CoreDataProperties.m或.swift,其中包含一个 Objective-C 类别或 Swift 扩展。
- 类定义生成相同的 Category/Extension 文件,另外生成Foo+CoreDataClass.m或.swift,包含类声明和定义。
因此,当习惯于旧 Xcode 的开发人员(如我)在新 Xcode 中开始项目时,您会看到问题发生。我们认为我们需要使用Create Managed Object Subclass菜单项来创建我们可以在 Project Navigator 中看到的文件,同时没有意识到我们在Codegen弹出窗口中的设置导致 Xcode 创建重复文件,Apple “聪明”不会显示在项目导航器中,因为他们不相信开发人员会阅读和注意标题中的注释// 此文件是自动生成的,不应编辑。
解决方案 1 - 使用旧方法
您只需一项设置即可禁用数据模型的所有自动Codegen :
- 打开问题目标的构建阶段(在Project Navigator中,选择项目,然后在出现的TARGETS列表中,选择问题目标,然后选项卡Build Phases)。
- 展开Compile Sources条目并找到问题数据模型(
.xcdatamodeld
文件)。
- 从编译列表中删除它
- 确保数据模型包含在Copy Bundle Resources列表中。
解决方案 2 - 初学者的核心数据魔法
在这里,您将全力以赴。
- 将您的数据模型保留在Compile Sources中。
- 在数据模型的每个实体检查器中,将Codegen设置为Class Definition。
- 在 Project Navigator 中,删除并丢弃所有Foo+CoreDataClass文件,并将所有Foo+CoreDataProperties.m或.swift文件重命名为Foo+MyProperties之类的名称。
- 在每个Foo+MyProperties.m或.swift文件中,如果有 Xcode 生成的属性,请删除这些属性,因为它们将在Codegen创建的隐藏文件中。
使用此解决方案,您的类定义会从每次构建的数据模型中自动生成。你甚至看不到他们。它是Core Data Magic,对初学者来说又好又简单。
解决方案 3 - 适用于大多数真实世界的应用程序
但是如果你真的想添加非托管属性,解决方案 2 就不好了。(Objective-C 不允许在类别中添加属性,而 Swift 不允许在扩展中添加存储的属性。)因此,在大多数实际应用程序中,您可能希望在解决方案 1 和 2 之间选择中间……</ p>
- 将您的数据模型留在编译源列表中
- 在数据模型的每个实体检查器中,将Codegen设置为Category/Extension。
- 在 Project Navigator 中,删除并丢弃任何Foo+CoreDataClass.m或.swift文件,并且为了减少将来的混淆,将任何Foo+CoreDataProperties.m或.swift文件重命名为Foo.m或.swift。
- 确保每个Foo.m或.swift文件都包含类定义,您可以在其中添加自己的非托管属性。
(Positron 对答案的致谢。我在这里的回答解释了为什么 Positron 的答案(我的解决方案 1)有效,并添加了解决方案 2 和解决方案 3。)