Xcode 8 generates broken NSManagedObject subclasses for iOS 10
Core DataNsmanagedobjectIos10Xcode8Core Data Problem Overview
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<Group> {
return NSFetchRequest<Group>(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)
Group+CoreDataProperties.swift:13:11: 'Group' is ambiguous for type lookup in this context
Group+CoreDataProperties.swift:15:16: Cannot specialize non-generic type 'NSFetchRequest'
Group+CoreDataProperties.swift:26:11: 'Group' is ambiguous for type lookup in this context
Group+CoreDataProperties.swift:43:82: 'SavedProfile' is ambiguous for type lookup in this context
- Group+CoreDataProperties.swift:13:11: 'Group' is ambiguous for type lookup in this context
- Group+CoreDataProperties.swift:15:16: Cannot specialize non-generic type 'NSFetchRequest'
- Group+CoreDataProperties.swift:26:11: 'Group' is ambiguous for type lookup in this context
Group+CoreDataProperties.swift:43:82: 'SavedProfile' is ambiguous for type lookup in this context
Core Data Solutions
Solution 1 - Core Data
I finally got mine to work. Here is what I did. (Flights is one of my entities)
I setup the xcdatamodeld as follows
And then the entity as
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 - Core Data
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 - Core Data
Solution 4 - Core Data
Try to set CodeGen: Manual/None Module: Current Product Module
It worked for me well, when I faced with the same problem.
Solution 5 - Core Data
You can try these steps
- Select the .xcdatamodeld file in Xocde Project Navigator
- In the Data Modul Inspector, make sure Codegen : Manual/None
- Then Edit -> Create NSManagedObject Subclass
- 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
Solution 6 - Core Data
If you have a legacy app and you wish to keep adding managed object classes manually
- Make sure your core data model codegen is set to Manual/None
- Select your core data model file
- Create managed object subclass
Solution 7 - Core Data
Delete the 3rd import
statement because it's empty.
Note: I don't know why this happens but I guess it's a bug in Xcode 8. Just delete it and it will work fine.
Solution 8 - Core Data
On Xcode 8.2.1, I made it the way: (thanks for Daniel Chepenko)
But Xcode 8.2.1 will add a stupid . into the generated files:
Just delete the . and it will run right.
Solution 9 - Core Data
I just had a problem where I just added a Person entity in my model to the Core Data template. Then generated the NSManagedObject subclass for for that and it won't compile, giving me a Linker Error. Turns out I am supposed to change the Codegen option to Manual/None to make it work (see bottom-right part of the picture).
Solution 10 - Core Data
I think it is a xcode issue, where xcode generates wrong syntax for core data category class.
I am creating a nsmanageobjectsubclass
for one entity AgentDetails
Here xcode create wrong code structure in AgentDetails+CoreDataClass.h
and AgentDetails+CoreDataClass.m
. Those have a code structure like:
And
So it is having duplicate interface issue as AgentDetails.h
have same interface.
Now to fix this you have to change the code in AgentDetails+CoreDataClass.h
and AgentDetails+CoreDataClass.m
like this:
Solution 11 - Core Data
In Data Model Inspector select Current Product Module under 'Module' and Manual/None under 'Codegen'. (This allows you to edit subclass files and to regenerate CoreDataProperties.swift when you modify your attributes under the same entity.)
You can then choose Create NSManagedObjectSubclass under Editor menu. Xcode will create 2 files for you YourEntity+CoreDataClass.swift and YourEntity+CoreDataProperties.swift. Notice if you don't have the latest Xcode (8.2.1), any optional/nonoptional properties that you set in your Model Inspector will not show up correctly. You can edit in YourEntity +CoreDataProperties.swift file.
Solution 12 - Core Data
I solved it like an example given below
Create CurrentcyPair.xcdatamodeld
select CurrentcyPair.xcdatamodeld and select Default -> Entity (CurrencyPair) , rename the class as (.ManagedCurrencyPair)
Select Entity and open Inspector. Set code gen at data model as Manual/None
Solution 13 - Core Data
Xcode 8.1 seems to be generating Model Class internally. Just delete the 2 classes created and you will still be able to use the entities in your code.
Here's the error message I was receiving
<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
Solution 14 - Core Data
Also, if you add NSManagedObject subclass yourself, don't forget to follow the following step: Go to '.xcdatamodeld' -> Choose the entity -> Show data model inspector -> Codegen -> Choose 'Manual/None'
This worked for me.
Solution 15 - Core Data
I found this Post from David Atkinson which is helpful in some way. If I generate the code the way David described. I just get the code with some Syntax errors and if I fix the errors everything works like before. There are no missing files starting with '.' any more.
The syntax errors i Have to correct are
-
the unnecessary import
-
and some public properties which are not intended to be public in my code
Solution 16 - Core Data
I am running the latest Xcode 8.1 beta (8T47) build.
According to the error log (see below), two copies of the autogenerated files are created. One copy is put in your Xcode project folder (the one visible in your directory on the left hand side toolbar of Xcode), and a second copy is created in your DerivedData folder for your project:
/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
Deleting the copies in your Xcode project directory will fix all issues, but proves pointless as you can no longer edit these files...
I wouldn't say this is a solution, rather just a half-assed way to get the project to build. Hopefully this bug will be addressed soon.
Solution 17 - Core Data
For me, I created CocoaTouch classes by subclassing of NSManagedObject
manually. I set the module as Current Product Module and Codegen as Category/Extension and it works well.
Solution 18 - Core Data
In my particular case, I had added CoreData to an existing project which already had a Model class by the same name as my entity. Deleting the old Model class fixed the problem, as its type was colliding with the new CoreData Entity class.
Solution 19 - Core Data
I'm putting my grain of salt given that I can see a lot of answers that solve the problem but are lacking the real reason behind what's really happening here.
I stumbled upon this very same issue and by doing a quick research I was able to find that:
-
Until Xcode 7, the default behavior for a Core Data entity was that the developer had to manually create and maintain the changes of the corresponding NSManagedObject subclasses. (This could, and still can be accomplished by making use of the editor menu selecting the "Create NSManagedObject subclass.." option).
-
Starting from Xcode 8, Apple has included a new setting right in the Data Model Inspector named Codegen to manage and maintain the NSManagedObject subclasses. The default value for this setting is "Class Definition" which tells Xcode to generate the NSManagedObject subclasses based on our defined entities in compile time and put them in the derived data folder.
Having our NSManagedObject subclasses within the project + the ones Xcode automatically generates lead us to the real reason behind the "Multiple commands produce..." compiling time error as we now have duplicated managed objects models!!!
The solution then is to use either one or another, not both! I personally prefer to have my managed object models within the project so I have changed this "Codegen" setting to "Manual/None". If you are not adding logic to the models I bet you could opt by removing your project's managed object models and let Xcode do its thing based on the "Class Definition" value for the mentioned setting. This is the right way to deal with this issue.
You can find a great article explaining all of this in detail here:
https://medium.com/@kahseng.lee123/core-data-codegen-explained-462c30341041
Solution 20 - Core Data
What you need to do is set the CodeGen to Category/Extension before you execute the Create NSManagedObject subclasses.
Solution 21 - Core Data
I have a Flights Entity and these settings in the Data Model Inspector worked for me :
-
Set the Name to nothing(You will see some grayed out text of "NSManagedObject"). The default will be written as "Flights" just remove that.
-
Nothing in the module."Global Namespace" greyed out is what you will see.
-
Codegen to Manual/None.
-
Then Goto Editor -> Create NSManagedObject Subclass to create the swift files
-
Rename the Flights+CoreDataClass.swift to just Flights.swift
Here's the link to the Screenshot(For some reason imgur was rejecting it :( ) https://drive.google.com/file/d/0B8a3rG93GTRedkhvbWc5Ujl4Unc/view?usp=sharing
Solution 22 - Core Data
After I renamed the following:
From: YourEntity+CoreDataClass.swift To: YourEntity.swift
and
From: YourEntity+CoreDataProperties.swift To: YourEntityCoreDataProperties.swift
then it works. It looks like "+" is causing the problem.