97

I am duplicating an existing Objective-C TV Show app to a new Swift version using Xcode 6.1 and am having some issues with CoreData.

I have created a model of 4 entities, created their NSManagedObject subclass (in Swift), and all files have the proper app targets set (for 'Compile Sources').

I am still getting this error whenever I try to insert a new entity:

CoreData: warning: Unable to load class named 'Shows' for entity 'Shows'. Class not found, using default NSManagedObject instead.

A few comments:

When saving to Core Data, I use the parent-child context way to allow background threading. I do this by setting up the ManagedObjectContext using:

lazy var managedObjectContext: NSManagedObjectContext? = {
  // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
  let coordinator = self.persistentStoreCoordinator
  if coordinator == nil {
    return nil
  }
  var managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
  managedObjectContext.persistentStoreCoordinator = coordinator
  return managedObjectContext
}()

and by saving data using:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
  var context = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
  context.parentContext = self.managedObjectContext!
  ...rest of core data saving code here...
})
Dan Beaulieu
  • 19,406
  • 19
  • 101
  • 135
JimmyJammed
  • 9,598
  • 19
  • 79
  • 146

13 Answers13

182

This warning is one of the quirks we have to deal with while the details of the Swift implementation are being ironed out. The warning occurs spuriously, i.e. your setup might work even if you do not follow the steps outlined below.

I have been able to get rid of it in most cases by making sure that the class is set correctly in the model editor. Unlike in many other SOF posts (including answers to this question), the suggestion to include the module name (like MyApp.Shows) has not helped me.

Make sure you check these three items:

1.
Version that works up to Xcode 7 beta 3

Up to XCode7 b3

Notice that I corrected your entity name to the more appropriate singular.

Version that works for Swift 2.0 in Xcode 7.1
(Should work for Xcode 7 beta 4 and above)

You need to delete the text "Current Product Module" in Module!

From Xcode7 beta 3

2.
You should also follow the frequent recommendation to include

@objc(Show)

just above your class.

Note: If you are using Xcode 7 beta 4 or later, this step is optional.

3.
Also make sure to cast the created managed object to the proper class, as the default would be just NSManagedObject.

var newShow = NSEntityDescription.insertNewObjectForEntityForName("Show", 
                 inManagedObjectContext: context) as Show
Mundi
  • 79,884
  • 17
  • 117
  • 140
  • 4
    Thanks! I did make the recommended naming convention updates, and it was the '@objc(Show)' that seems to do the trick in fixing the 'Unable to load class...' error. Much appreciated! – JimmyJammed Oct 30 '14 at 22:12
  • Hi @Mundi. Thank you so much! would you still remember where was the source? – iamdavidlam Dec 03 '14 at 14:19
  • @iamdavidlam I do not understand the question. What source? – Mundi Dec 03 '14 at 14:20
  • "Other suggestions circle around the recommendation to include @objc(Show) just above your class." this solved my issue. and i was wondering where did you come across this suggestion and what does it really to :) – iamdavidlam Dec 03 '14 at 14:25
  • 1
    See e.g. [this question](http://stackoverflow.com/q/25076276/427083). There is enough information there to understand what's going on. – Mundi Dec 03 '14 at 14:37
  • @iamdavidlam dunno if you figured it out but for anyone looking at this in the future, simply add @objc(MyEntity) above your entity class declaration to fix this issue https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html – Jonathan Crowe Jan 24 '15 at 20:10
  • Setting the class name (which for me had somehow become "PRODUCT_MODULE_NAME.Person" instead of just "Person" didn't fix it, but the objc() trick did. – SarahR Apr 14 '15 at 22:58
  • 4
    Interestingly enough, [I had to _remove_](http://stackoverflow.com/a/30873296/2446155) `@objc(MyClass)` – Andrew Jun 16 '15 at 16:34
  • I also had to remove the @objc(MyClass) to make it work. – Kent Jul 29 '15 at 04:29
  • 1
    @Mundi, you might want to update your answer again. See khunshan's answer update. – Suragch Aug 12 '15 at 06:55
  • I hate this problem. I keep coming to this answer as it occurs on each CoreData Model Migration. – Gugulethu Jun 06 '16 at 11:10
  • I have no idea what's going on with my Xcode (9.1) - I need to have both versions of the "Module" trick to make my project work. Two entities have "Current Product Module" (created yesterday), two have an empty module (created today). If I change either one the build fails. I wonder which way Xcode wants tomorrow. – Paco1 Nov 14 '17 at 12:04
80

SWIFT 2 / XCODE 7 Update:

This issue (see my April 3 comment on this answer as well) is resolved in Swift 2 and XCode 7 beta release by Apple. So you actually now do not need @objc(myEntity) in Swift as answered by Mundi or using "MyAppName." before your Class name. It will stop working. So remove these, just put Class name in File and select Current Working Module as Module and cheers!

Selecting current working module

But for those using @objc(myEntity) in Swift (like me), you can use this other solution instead which works smoothly.

In the xcdatamodel correct class in. It should look like this:

Setting the class

Here you go. Module.Class is the pattern for CoreData in Swift and XCode 6. You will also need the same procedure when using Custom Policy class in Model Policy or other CoreData stuff. A note: In image, The Name and Class should be Car and MyAppName.Car (or whatever the name of your entity). Here, User is a typo.

khunshan
  • 2,662
  • 4
  • 28
  • 34
  • The problem with this solution is that auto generating entity classes will no longer work properly (it will generate only one class with the module name). See: [Create NSManagedObject subclass not generating properly](http://stackoverflow.com/a/29423883/1409907). – Milos Apr 02 '15 at 23:08
  • You need to apply the solution after generating NSManagedObject entity classes. Probably a xcode 6.xx bug to be removed. – khunshan Apr 03 '15 at 11:07
  • 2
    Yes, this will undoubtedly be resolved. Auto generated classes should be already adorned with @objc() or, more likely, Apple will make this unnecessary to begin with. – Milos Apr 03 '15 at 12:29
  • 2
    For people still reading this. using '**MyAppName.Car**' did not work for me, it did work when I removed the '**MyAppName.**' part. So just `Car` for both fields did the trick. – Gideon Apr 11 '15 at 09:16
  • I've seen this method recommended in [tutorials](http://jamesonquave.com/blog/core-data-in-swift-tutorial-part-1/), but as of Xcode 7 / Swift 2, if you try to prepend with "MyAppName.", Xcode will remove the period, preventing it from working. @Santa Claus's answer works for XCode 7. – sudo make install Jul 27 '15 at 21:32
  • Just tried converting over to Xcode7, beta4. Not ready for prime time AFAIC. Ran into abort issues, with the compiler crashing. Reverted back to prior code version. Going to use Objective-C NSModelSubclasses as a work around. – Chris Prince Aug 02 '15 at 20:16
  • @khunshan Just checked this again. I think you should remove the strikethrough through the sentence containing my name. My solution still works. Removing `@obj(MyClass)` apparently has nothing to do with it (false positive). I have indicated in my original answer that it sometimes works anyway, who knows why. – Mundi Nov 16 '15 at 06:13
  • Yep. I always make sure I have the latest official Xcode along with the latest beta (if available). No apparent change in 7.1.1 (7B1005). – Mundi Nov 16 '15 at 13:46
  • Curious as to whether MyAppName is actually the package name for the app or actually the app name – Jacob Jennings Nov 25 '15 at 20:42
  • @JacobJennings You do not need now as the bug is fixed which I also reported after my April 3 comment. :) – khunshan Dec 15 '15 at 14:46
  • 1
    you Champ!!!! let person = NSEntityDescription.insertNewObject(forEntityName: "Person", into: context) as! Person – Abhimanyu Daspan Aug 24 '17 at 06:51
36

When using Xcode 7 and purely Swift, I actually had to remove @objc(MyClass) from my auto-generated NSManagedObject subclass (generated from Editor > Create NSManagedObject Subclass...).

Andrew
  • 15,357
  • 6
  • 66
  • 101
13

In Xcode 7 beta 2 (and I believe 1), in the model configuration a new managed object of type File is set to the Module Current Product Module and the class of the object is shown in configuration as .File.

Module of managed object type set to "Current Product Module" in Xcode 7

Deleting the module setting so it is blank, or removing the full stop so the class name in configuration is just File are equivalent actions, as each causes the other change. Saving this configuration will remove the error described.

Module of managed object set to be blank in Xcode 7

Duncan Babbage
  • 19,972
  • 4
  • 56
  • 93
9

In Xcode 6.1.1 you do not need to add the @objc attribute since the base entity is a subset of an objc class (NSManagedObject) (see Swift Type Compatibility. In CoreData the full Module.Class name is required. Be aware the Module name is what is set in Build Settings -> Packaging -> Product Module Name. By default this is set to $(PRODUCT_NAME:c99extidentifier) which will be the Target's name.

Jim Malak
  • 179
  • 1
  • 2
  • Yes! This is the modern answer (xcode 6.3.2). Using the right bundle name is key. In my case, it had transformed `my-product` into `my_product`, and this made all the difference to Core Data. – SimplGy May 26 '15 at 04:13
6

With xCode 7 and Swift 2.0 version, you don't need to add @objc(NameOfClass), just change the entity settings in "Show the Data Model Inspector" tab like below -

Name - "Your Entity Name"

Class - "Your Entity Name"

Module - "Current Product Module"

enter image description here

Code for Entity class file will be like (in my code Entity is Family) -

import UIKit
import CoreData

class Family: NSManagedObject {

   @NSManaged var member : AnyObject
}

This example is working fine in my app with xCode 7.0 + swift 2.0

Himanshu Mahajan
  • 4,779
  • 2
  • 36
  • 29
3

Do not forget to replace PRODUCT_MODULE_NAME with your product module name.

When a new entity is created, you need to go to the Data Model Inspector (last tab) and replace PRODUCT_MODULE_NAME with your module name, or it will result a class not found error when creating the persistent store coordinator.

Kof
  • 23,893
  • 9
  • 56
  • 81
2

You also need to use (at least with Xcode 6.3.2) Module.Class when performing your cast for example: Assuming your module (i.e. product name) is Food and your class is Fruit

let myEntity =  NSEntityDescription.entityForName("Fruit", inManagedObjectContext: managedContext)

let fruit = NSManagedObject(entity: myEntity!, insertIntoManagedObjectContext:managedContext) as! Food.Fruit

Recap:

  • Include module name when defining entity in Data Model Editor (Name: Fruit, Class: Food.Fruit)
  • When accessing the entity in code (i.e.SWIFT), cast it with Module.class (e.g. Food.Fruit)
Wizkid
  • 1,015
  • 10
  • 10
  • Thank you, the second point is very important. I had to use "Module.Class" when casting it. – Zoyt May 26 '15 at 06:38
2

I also encountered a similar problem, follow these steps to resolve:

  1. The parent is NSManagedObject, not NSObject
  2. The module of an entity is default, not "Current Product Module"
WSJ
  • 21
  • 3
1

Changing the Entity Class name in the Data Model editor to correspond to the class in question and adding @objc(NameOfClass) to file of each NSManagedObject right above the class declaration solved this problem for me during Unit Testing.

user3269767
  • 11
  • 1
  • 1
1

Most of these answers still seem to apply in Xcode 14. However, my Swift NSManagedObject subclass is included in a custom framework. So what worked for me is: In that Entity inspector, in that Module field (see screenshot in answer by khunsan), type in the name of your framework, for example, MyFramework.

Jerry Krinock
  • 4,860
  • 33
  • 39
0

What worked for me (Xcode 7.4, Swift) is changing the class name to <my actual class name>.<entity name> in the Entity inspector, 'Class' box.

My initiator of the Managed object subclass, looks like this:

    convenience init(<properties to init>) {
    let entityDescr = NSEntityDescription.entityForName("<entity class name>", inManagedObjectContext: <managed context>)
    self.init(entity: entityDescr!, insertIntoManagedObjectContext: <managed context>)}
    //init properties here
mark
  • 181
  • 6
0

For Xcode 11.5: if Codegen property is class Definition, and if you are not getting a suggestion for the entity you created in xcdatamodel. Try to quit Xcode and reopen your project again. It works for me. This answer is only if you are not getting suggestions but if your file doesn't get generated try any above answer.

Gulshan Kumar
  • 61
  • 1
  • 8