【问题标题】:Xcode 8 generates broken NSManagedObject subclasses for iOS 10Xcode 8 为 iOS 10 生成损坏的 NSManagedObject 子类
【发布时间】:2017-02-01 02:31:26
【问题描述】:

我最近将我的 iOS 应用程序项目更新到 iOS 10。现在我正在尝试更改我的应用程序的核心数据模型,但 Xcode 生成的新 NSManagedObject 子类已损坏。我也尝试修复子类手册,但这不起作用。

Core Data Model 的最低工具版本设置为 Xcode 7.0,代码生成语言设置为 Swift。

这是 Xcode 生成的代码:

import Foundation
import CoreData
import 

extension Group {

    @nonobjc public class func fetchRequest() -> NSFetchRequest {
        return NSFetchRequest(entityName: "Group");
    }

    @NSManaged public var name: String?
    @NSManaged public var platform: NSNumber?
    @NSManaged public var profiles: NSOrderedSet?

}

// MARK: Generated accessors for profiles
extension Group {

    @objc(insertObject:inProfilesAtIndex:)
    @NSManaged public func insertIntoProfiles(_ value: SavedProfile, at idx: Int)

    @objc(removeObjectFromProfilesAtIndex:)
    @NSManaged public func removeFromProfiles(at idx: Int)

    @objc(insertProfiles:atIndexes:)
    @NSManaged public func insertIntoProfiles(_ values: [SavedProfile], at indexes: NSIndexSet)

    @objc(removeProfilesAtIndexes:)
    @NSManaged public func removeFromProfiles(at indexes: NSIndexSet)

    @objc(replaceObjectInProfilesAtIndex:withObject:)
    @NSManaged public func replaceProfiles(at idx: Int, with value: SavedProfile)

    @objc(replaceProfilesAtIndexes:withProfiles:)
    @NSManaged public func replaceProfiles(at indexes: NSIndexSet, with values: [SavedProfile])

    @objc(addProfilesObject:)
    @NSManaged public func addToProfiles(_ value: SavedProfile)

    @objc(removeProfilesObject:)
    @NSManaged public func removeFromProfiles(_ value: SavedProfile)

    @objc(addProfiles:)
    @NSManaged public func addToProfiles(_ values: NSOrderedSet)

    @objc(removeProfiles:)
    @NSManaged public func removeFromProfiles(_ values: NSOrderedSet)

}

编辑:这些是 Xcode 给出的具体错误:

1. Group+CoreDataProperties.swift:13:1: Expected identifier in import declaration (the empty import)
2. Group+CoreDataProperties.swift:13:11: 'Group' is ambiguous for type lookup in this context
3. Group+CoreDataProperties.swift:15:16: Cannot specialize non-generic type 'NSFetchRequest'
4. Group+CoreDataProperties.swift:26:11: 'Group' is ambiguous for type lookup in this context
4. Group+CoreDataProperties.swift:43:82: 'SavedProfile' is ambiguous for type lookup in this context

【问题讨论】:

  • 您能解释一下是什么损坏了吗?是第 3 行的空导入吗?
  • @DavidAtkinson 是的,Xcode 给出了空导入的错误。我还在问题中添加了其他 4 个错误。
  • 不幸的是,我认为这是 Xcode 8 和 8.1 beta 中的一个错误。如果您自动生成,它还会显示派生数据文件所在的位置,但 Xcode 正在寻找带有 .在文件名的开头。如果您手动修复该问题,则会收到虚假错误,例如您列出的错误。我还没有找到解决方法,我不敢相信更多的人没有发现这个错误,因为它似乎阻止了你在应用程序中处理核心数据。 openradar.me/27151410
  • @Longmang 谢谢你的解释。希望苹果能尽快针对这个问题发布更新。

标签: core-data nsmanagedobject ios10 xcode8


【解决方案1】:

我终于开始工作了。这就是我所做的。 (航班是我的实体之一)

我设置 xcdatamodeld 如下

然后实体为

然后我使用 Editor -> 创建 NSManagedObject 子类

这会为我的航班实体创建两个文件

Flights+CoreDataProperties.swift

Flights+CoreDataClass.swift

我将 Flight+CoreDataClass.swift 重命名为 Flight.swift

Flights.swift 只是

import Foundation
import CoreData

@objc(Flights)
public class Flights: NSManagedObject {

}

Flights+CoreDataProperties.swift 是

import Foundation
import CoreData


extension Flights {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Flights> {
        return NSFetchRequest<Flights>(entityName: "Flights");
    }

    @NSManaged public var ...
}

这似乎对我有用。我无法让 Codegen 以任何其他方式工作,即使我尝试了许多现有的建议。

这也让我摸不着头脑,我将其添加为辅助。不要忘记使用 FetchRequest 的新泛型版本,您可以做到这一点

let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Flights")

【讨论】:

  • 这是对我有用的答案。我花了半天时间寻找解决方案,这是一个简单的设置。当我开始挣扎时,我应该默认寻找这样的东西。谢谢!
  • 这对我有用,非常感谢!我也花了太长时间试图找到解决方案,结果却是极度沮丧。我尝试了所有你能想到的方法,除了这个没有任何效果。您必须为Codegen 选项选择Manual/None。如果它保持为Class Definition,它似乎不起作用。再次感谢您的帮助!
  • 谢谢。这对我也有用。但这太棘手了。这是 Xcode 的 bug 吗?
  • 这对我不起作用。我的解决方案是将 Tools version minimun 更改为 Xcode 7.3 .... 很奇怪:S
  • 肯定也帮助了我。谢谢
【解决方案2】:

我相信您在生成 NSManagedObject 子类文件后遇到这些错误的原因可能与您的数据模型更改时选择的 Codegen 选项有关。

我不认为这是一个错误。至少在 Xcode 8.1 (8B62) 中没有。

我遇到了类似的问题,并通过将 Codegen 选项更改为“手动/无”并将模块选项保留为“全局命名空间”来修复它。然后我生成了我的 NSManagedObject 子类文件。但是,根据您的情况,您甚至可能不需要生成 NSManagedObject 子类。

下面是关于实体 Codegen 选项的更多详细信息,基于我对 Apple 文档、Apple 开发者论坛和我自己项目的测试的审查。

选项 1:“类定义”

  • 将此视为“即插即用”选项

  • 使用模型编辑器创建实体和关联属性 您希望 Core Data 管理。

  • 不要使用 NSMangagedObject 子类生成器。所需的 Xcode 会自动为你生成文件(不管怎样 不会出现在您的项目导航器中)。

  • 如果您确实生成了 NSManagedObject 文件,Apple 会告诉您 这些文件不应在所述的标头 cmets 中进行编辑 文件。如果您确实需要编辑这些文件,那么这是一个好兆头 您需要使用另一个 Codegen 选项。

  • 为您的实体保留默认的类选项(模块 = 全局 命名空间和 Codegen = 类定义)

  • 如果你需要重写 NSManagedObject 的方法,你可以 使用 Class 选项下的 Name 创建一个扩展。

    // Optional extension in Entity.swift extension Entity { // Override NSManagedObject methods }

选项 2:“手动/无”

  • 与选项 1 类似,不同之处在于您可以查看和编辑 NSManagedObject 子类文件。

  • 使用模型编辑器创建实体和关联属性 您希望 Core Data 管理。

  • 在使用 NSManagedObject 子类生成器之前,设置 Codgen 实体的“手动/无”选项。模块选项应该是 全局命名空间。

  • 添加/删除/更新属性后,您有两种选择:(1) 手动更新为您生成的 NSManagedObject 文件 或 (2) 再次使用 NSManagedObject 子类生成器(这将 只更新 Entity+CoreDataProperties.swift 文件)。

  • 同样,如果你需要重写 NSManagedObject 中的方法,你 可以创建一个扩展。扩展应该在 Entity+CoreDataClass.swift 文件而不是 Entity+CoreDataProperties.swift 文件(此文件可能会因 模型编辑器更改)。

    // Optional extension in Entity+CoreDataClass.swift extension Entity { // Override NSManagedObject methods }

选项 3:“类别/扩展”

  • 如果您有不需要的自定义属性,请使用此选项 由 Core Data 管理。

  • 使用模型编辑器创建实体和关联属性 您希望 Core Data 管理。

  • 确保将模块选项设置为当前产品模块,并且 Codegen 选项设置为“Category/Extension”。

  • 使用您自己的属性创建您自己的 NSManagedObject 子类 会自行管理。

  • 不要使用 NSMangagedObject 子类生成器。所需的 Xcode 会自动为你生成文件(不管怎样 不会出现在您的项目导航器中)。

    // Subclass NSManagedObject in Entity.swift class Entity: NSManagedObject { // Self managed properties }

    // Optional extension in Entity.swift extension Entity { // Override NSManagedObject methods }

【讨论】:

  • 您能否详细介绍一下类别/扩展路径?我在数据模型中添加了一个瞬态属性,但我不知道如何编辑生成的文件,因为我在左侧文件资源管理器中看不到它们。它们在导入标头时出现,因此它们必须在某处生成。
  • 谢谢。您的回答非常有帮助。你也可以看看here。我的问题集中在使用 Manual/None 时如何更改属性
【解决方案3】:
  1. 为解决此问题,请删除应用的派生数据。

  2. 然后将 Module 更改为 Current Product Module 并将 Codegen 更改为 Manual/None强>.

【讨论】:

  • 如果您希望跳过删除派生数据,请删除您生成的 NSManagedObject 子类,进行上述更改,保存模型文件,然后再次创建 NSManagedObject 子类。
  • 这是解决方法
【解决方案4】:

尝试设置 CodeGen:Manual/None 模块:当前产品模块

当我遇到同样的问题时,它对我很有效。

【讨论】:

    【解决方案5】:

    你可以试试这些步骤

    1. 在 Xocde Project Navigator 中选择 .xcdatamodeld 文件
    2. Data Modul Inspector 中,确保 CodegenManual/None
    3. 然后编辑 -> 创建 NSManagedObject 子类
    4. 清理产品并重建

    这行得通吗?如果没有

    确保所有Entities名称不同。您可以在 Build Phases -> Compile Sources 中找到这些类。重命名类或实体(如果它们重复)

    或者

    您可以在项目文件夹中运行此命令以获取更多错误信息

    xcodebuild -verbose

    当我遇到此问题时收到此消息

    重复的符号 _OBJC_CLASS__$_RandomList 在:

    xxxx/RandomList.o

    xxxx/RandomList+CoreDataClass.o

    RandomList.hRandomList+CoreDataClass.h编译时符号相同

    我认为为什么 Xcode 没有警告你,但编译器会抛出错误

    希望对你有帮助

    【讨论】:

    • 如果您已经创建了这两个文件,那么只需 #2 和 #3 就足够了。它对我有用。
    【解决方案6】:

    如果您有旧版应用并且希望继续手动添加托管对象类

    1. 确保您的核心数据模型代码生成设置为手动/无
    2. 选择您的核心数据模型文件
    3. 创建托管对象子类

    【讨论】:

      【解决方案7】:

      删除第三条import 语句,因为它是空的。

      注意:我不知道为什么会这样,但我猜这是 Xcode 8 中的一个错误。删除它就可以正常工作。

      【讨论】:

      • 感谢您的回答!不幸的是,删除三个空的import 语句并不能修复所有错误。
      • 这行得通。哇...这到底是谁 QA 的东西... Apple cmon
      • 这对我有用“手动/无”选项和 Xcode 8.0....至少没有构建错误
      【解决方案8】:

      Xcode 8.2.1 上,我做到了:(感谢 Daniel Chepenko

      但是 Xcode 8.2.1 会在生成的文件中添加一个愚蠢的 .

      只需删除即可正常运行。

      【讨论】:

      • 您可以使用Xcode 7.3.1设计coredata并生成相关类,然后退出Xcode 7.3.1并使用Xcode 8打开项目。 (我最近的项目也是用这种方式,已经验证了:])
      【解决方案9】:

      我刚刚在我的模型中将 Person 实体添加到 Core Data 模板时遇到了问题。然后为此生成 NSManagedObject 子类,它不会编译,给我一个链接器错误。原来我应该将 Codegen 选项更改为 Manual/None 以使其工作(参见图片的右下部分)。

      【讨论】:

      • 这对我有用,因为我已经生成了 NSManagedObject 子类。
      【解决方案10】:

      我认为这是一个 xcode 问题,其中 xcode 为核心数据类别类生成错误的语法。 我正在为一个实体 AgentDetails 创建一个 nsmanageobjectsubclass

      这里 xcode 在AgentDetails+CoreDataClass.hAgentDetails+CoreDataClass.m 中创建了错误的代码结构。它们的代码结构如下:

      还有

      所以它有重复的接口问题,因为AgentDetails.h 有相同的接口。

      现在要解决此问题,您必须更改 AgentDetails+CoreDataClass.h 中的代码

      AgentDetails+CoreDataClass.m 这样:

      【讨论】:

        【解决方案11】:

        在 Data Model Inspector 中,选择“Module”下的 Current Product Module 和“Codegen”下的 Manual/None。 (这允许您在修改同一实体下的属性时编辑子类文件并重新生成 CoreDataProperties.swift。)

        然后您可以在编辑器菜单下选择创建 NSManagedObjectSubclass。 Xcode 将为您创建 2 个文件 YourEntity+CoreDataClass.swift 和 YourEntity+CoreDataProperties.swift。请注意,如果您没有最新的 Xcode (8.2.1),您在模型检查器中设置的任何可选/非可选属性都不会正确显示。你可以编辑 YourEntity +CoreDataProperties.swift 文件。

        【讨论】:

          【解决方案12】:

          我像下面给出的例子一样解决了它

          创建CurrentcyPair.xcdatamodeld

          选择 CurrentcyPair.xcdatamodeld 并选择 Default -> Entity (CurrencyPair) ,将类重命名为 (.ManagedCurrencyPair)

          选择实体并打开检查器。将数据模型的代码生成设置为Manual/None

          【讨论】:

            【解决方案13】:

            Xcode 8.1 似乎在内部生成模型类。只需删除创建的 2 个类,您仍然可以在代码中使用实体。

            这是我收到的错误消息

            <unknown>:0: error: filename "Recipe+CoreDataProperties.swift" used twice: '/Users/Rick/Desktop/Devslop/Rick Recipe/Recipe+CoreDataProperties.swift' and '/Users/Rick/Library/Developer/Xcode/DerivedData/Rick_Recipe-cctgjudvqobxlwetbcwmzrgxigwg/Build/Intermediates/Rick Recipe.build/Debug-iphonesimulator/Rick Recipe.build/DerivedSources/CoreDataGenerated/Rick_Recipe/Recipe+CoreDataProperties.swift'
            <unknown>:0: note: filenames are used to distinguish private declarations with the same name
            Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
            

            【讨论】:

              【解决方案14】:

              另外,如果您自己添加 NSManagedObject 子类,请不要忘记执行以下步骤: 转到“.xcdatamodeld” -> 选择实体 -> 显示数据模型检查器 -> Codegen -> 选择“手动/无”

              这对我有用。

              【讨论】:

                【解决方案15】:

                我发现这个Post from David Atkinson 在某种程度上很有帮助。 如果我按照大卫描述的方式生成代码。我只是得到了一些语法错误的代码,如果我修复了错误,一切都会像以前一样工作。没有以“。”开头的文件丢失。没有了。

                我必须纠正的语法错误是 - 不必要的导入 - 以及一些不打算在我的代码中公开的公共属性

                【讨论】:

                  【解决方案16】:

                  我正在运行最新的 Xcode 8.1 beta (8T47) 版本。

                  根据错误日志(见下文),自动生成文件的两个副本被创建。一个副本放在您的 Xcode 项目文件夹中(在 Xcode 左侧工具栏上的目录中可见),第二个副本在您的项目的 DerivedData 文件夹中创建:

                  /Users/<your name>/Library/Developer/Xcode/DerivedData/<your app>-axhtnodotznxnrenefflktnxfeal/Build/Intermediates/<your app>.build/Debug-iphonesimulator/<your app>.build/DerivedSources/CoreDataGenerated/<your app>/<class name>+CoreDataProperties.swift
                  /Users/<your name>/Library/Developer/Xcode/DerivedData/<your app>-axhtnodotznxnrenefflktnxfeal/Build/Intermediates/<your app>.build/Debug-iphonesimulator/<your app>.build/DerivedSources/CoreDataGenerated/<your app>/<class name>+CoreDataClass.swift
                  

                  删除 Xcode 项目目录中的副本将解决所有问题,但证明毫无意义,因为您无法再编辑这些文件...

                  我不会说这是一个解决方案,而只是让项目得以构建的一种半途而废的方式。希望这个错误会很快得到解决。

                  【讨论】:

                    【解决方案17】:

                    对我来说,我通过手动继承 NSManagedObject 来创建 CocoaTouch 类。我将模块设置为当前产品模块,将 Codegen 设置为类别/扩展,它运行良好。

                    【讨论】:

                      【解决方案18】:

                      在我的特定情况下,我已将 CoreData 添加到现有项目中,该项目已经有一个与我的实体同名的模型类。删除旧的 Model 类解决了这个问题,因为它的类型与新的 CoreData Entity 类发生冲突。

                      【讨论】:

                        【解决方案19】:

                        鉴于我可以看到很多解决问题的答案 缺乏这里真正发生的事情背后的真正原因。

                        我偶然发现了同样的问题,通过快速研究,我发现:

                        • 在 Xcode 7 之前,Core Data 实体的默认行为是开发人员必须手动创建和维护相应 NSManagedObject 子类的更改。 (这可以并且仍然可以通过使用编辑器菜单选择“创建 NSManagedObject 子类..”选项来完成)。

                        • 从 Xcode 8 开始,Apple 在 Data Model Inspector 中包含了一个名为 Codegen 的新设置,用于管理和维护 NSManagedObject 子类。此设置的默认值是“Class Definition”,它告诉 Xcode 在编译时根据我们定义的实体生成 NSManagedObject 子类,并将它们放在派生数据文件夹中。

                        在项目中拥有我们的 NSManagedObject 子类 + Xcode 自动生成的子类导致我们发现“多个命令产生...”编译时错误背后的真正原因,因为我们现在有重复的托管对象模型!!!

                        然后解决方案是使用其中一个或另一个,而不是两者都使用!我个人更喜欢在项目中使用我的托管对象模型,因此我已将此“Codegen”设置更改为“Manual/None”。如果您没有向模型添加逻辑,我敢打赌,您可以选择删除项目的托管对象模型,并让 Xcode 根据上述设置的“类定义”值来做它的事情。这是处理这个问题的正确方法。

                        您可以在此处找到一篇详细解释所有这些的精彩文章:

                        https://medium.com/@kahseng.lee123/core-data-codegen-explained-462c30341041

                        【讨论】:

                          【解决方案20】:

                          您需要做的是在执行 Create NSManagedObject 子类之前将 CodeGen 设置为 Category/Extension。

                          【讨论】:

                            【解决方案21】:

                            我有一个航班实体,数据模型检查器中的这些设置对我有用:

                            1. 将名称设置为空(您将看到“NSManagedObject”的一些灰色文本)。默认将写为“航班”,只需将其删除即可。

                            2. 模块中没有任何内容。您将看到灰色的“全局命名空间”。

                            3. 代码生成为手动/无。

                            4. 然后转到编辑器 -> 创建 NSManagedObject 子类以创建 swift 文件

                            5. 将 Flights+CoreDataClass.swift 重命名为 Flight.swift

                            这是截图的链接(出于某种原因,imgur 拒绝了它:()https://drive.google.com/file/d/0B8a3rG93GTRedkhvbWc5Ujl4Unc/view?usp=sharing

                            【讨论】:

                              【解决方案22】:

                              在我重命名以下内容后:

                              来自:YourEntity+CoreDataClass.swift 收件人:YourEntity.swift

                              来自:YourEntity+CoreDataProperties.swift 收件人:YourEntityCoreDataProperties.swift

                              然后就可以了。看起来是“+”导致了问题。

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2016-12-29
                                • 1970-01-01
                                • 2016-11-12
                                • 2016-10-20
                                • 2014-12-21
                                相关资源
                                最近更新 更多