Xcode 8 generates broken NSManagedObject subclasses for iOS 10

41,248

Solution 1

I finally got mine to work. Here is what I did. (Flights is one of my entities)

I setup the xcdatamodeld as follows

enter image description here

And then the entity as

enter image description here

Then I used Editor -> Create NSManagedObject Subclass

This creates two files for my flights entity

Flights+CoreDataProperties.swift

Flights+CoreDataClass.swift

I renamed Flights+CoreDataClass.swift to Flights.swift

Flights.swift is just

import Foundation
import CoreData

@objc(Flights)
public class Flights: NSManagedObject {

}

Flights+CoreDataProperties.swift is

import Foundation
import CoreData


extension Flights {

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

    @NSManaged public var ...
}

This appears to work for me.I could not get Codegen to work in any other way, even though I tried many of the suggestions that were out there.

Also this had me scratching my head for a while and I add it as an assist. Don't forget with the new Generics version of the FetchRequest you can do this

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

Solution 2

I believe the reason you encountered those errors after generating the NSManagedObject subclass files may be related to the Codegen option that was selected at the time your data model changed.

I do not think this is a bug. At least not in Xcode 8.1 (8B62).

I encountered a similar issue and fixed it by changing the Codegen option to "Manual/None" and leaving the Module option as "Global Namespace". I then generated my NSManagedObject subclass files. However, depending on your situation, you may not even need to generate the NSManagedObject subclasses.

Below are more details on the entity Codegen options based my review of Apple's documentation, the Apple developer's forum and testing with my own project.

Option 1: "Class Definition"

  • Think of this as the "plug and play" option

  • Use the model editor to create the entities and associated attributes that you want Core Data to manage.

  • Do not use the NSMangagedObject subclass generator. The required files are automatically generated for you by Xcode (however they do not show up in your project navigator).

  • If you do generate the NSManagedObject files, Apple tells you that these files should not be edited in the header comments of said files. If you do need to edit these files, then this is good sign that you need to use another Codegen option.

  • Leave the default Class options for your entity (Module = Global Namespace and Codegen = Class Definition)

  • If you need to override methods of the NSManagedObject, you can create an extension using the Name under the Class option.

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

Options 2: "Manual/None"

  • Similar to Option 1, except that you can see and edit the NSManagedObject subclass files.

  • Use the model editor to create the entities and associated attributes that you want Core Data to manage.

  • Before using the NSManagedObject subclass generator, set the Codgen option to "Manual/None" for the entity. The Module option should be Global Namespace.

  • After you add/remove/update an attribute, you have two choices: (1) Manually update the NSManagedObject files that were generated for you OR (2) Use the NSManagedObject subclass generator again (this will only update the Entity+CoreDataProperties.swift file).

  • Again, if you need to override and methods from NSManagedObject, you can create an extension. The extension should be created in the Entity+CoreDataClass.swift file and not the Entity+CoreDataProperties.swift file (this file could be updated due to model editor changes).

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

Option 3: "Category/Extension"

  • Use this option if you have custom properties that do not need to be managed by Core Data.

  • Use the model editor to create the entities and associated attributes that you want Core Data to manage.

  • Ensure the Module option is set to Current Product Module and the Codegen option is set to "Category/Extension".

  • Create your own NSManagedObject subclass with the properties that you will self manage.

  • Do not use the NSMangagedObject subclass generator. The required files are automatically generated for you by Xcode (however they do not show up in your project navigator).

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

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

Solution 3

  1. To solve this problem delete the derived data of the app.

  2. Then change the Module to Current Product Module and also make changes in Codegen to Manual/None.

  3. List item

Solution 4

Try to set CodeGen: Manual/None Module: Current Product Module

It worked for me well, when I faced with the same problem.

enter image description here

Solution 5

You can try these steps

  1. Select the .xcdatamodeld file in Xocde Project Navigator
  2. In the Data Modul Inspector, make sure Codegen : Manual/None
  3. Then Edit -> Create NSManagedObject Subclass
  4. Clean product and rebuild

Is that work? If not

Make sure you all class has not the same name with Entities. You can find these class in Build Phases -> Compile Sources. Rename the class or Entities if they duplicated

Or

You can run this command to in your project folder to get more error info

xcodebuild -verbose

I got this message when i have this problem

duplicate symbol _OBJC_CLASS_$_RandomList in:

xxxx/RandomList.o

xxxx/RandomList+CoreDataClass.o

RandomList.h and RandomList+CoreDataClass.h have a same symbol when compiling

I think that why Xcode did not warn you, but Compiler will throw error

Hope this will help you

Share:
41,248
Remco Beugels
Author by

Remco Beugels

Updated on July 08, 2022

Comments

  • Remco Beugels
    Remco Beugels almost 2 years

    I updated my iOS app project recently to iOS 10. Now I'm trying to change the Core Data Model of my app but the new NSManagedObject subclasses which Xcode generates are broken. I also tried to fix the subclasses manual but this doesn't work.

    The minimum tools version for the Core Data Model is set to Xcode 7.0 and code generation language is set to Swift.

    This is the code which Xcode generates:

    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)
    
    }

    Edit: These are the specific errors which Xcode gives:

    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