15

I'm testing swift with CoreData and I created the following code:

import UIKit
import CoreData

class Contact: NSManagedObject {

    @NSManaged var name: String
    @NSManaged var email: String

    class func execute(){
        let appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
        let context:NSManagedObjectContext = appDel.managedObjectContext!

        let entityDescripition = NSEntityDescription.entityForName("Contact", inManagedObjectContext: context)
        let contact = Contact(entity: entityDescripition!, insertIntoManagedObjectContext: context)

        contact.name = "john Apleesee"
        contact.email = "john@apple.com"

        context.save(nil)

        let fetch:NSFetchRequest = NSFetchRequest(entityName: "Contact")
        var result = context.executeFetchRequest(fetch, error: nil) as [Contact]

        let firstContact = result[0] as Contact  //  <<-- error !

        println("\(firstContact.name)")
        println("\(firstContact.email)")

    }

}

When I run:

Contact.execute()

Then the compiler throw this error:

fatal error: NSArray element failed to match the Swift Array Element type

when I try to get values from array:

 let firstContact = result[0] as Contact

I guess the problem is in executeFetchRequest. On Objective-c the return type of executeFetchRequest is a NSArray. Now on Swift the return type is a [AnyObject]?.

I tried to cast the [AnyObject]? result to NSArray, but Xcode said:

 Cannot convert the expression's type '[AnyObject]?' to type 'NSArray' 

What I'm doing wrong ?

I'm using: Xcode 6.0 (6A313) GM and OSX 10.9.4

Update:
-----------

If I get executeFetchRequest result as an optional array and use [NSManagedObject] instead of [Contact] it works.

if let result: [NSManagedObject]? = context.executeFetchRequest(fetch, error: nil) as? [NSManagedObject] {

        let firstContact: NSManagedObject = result![0]

        let name = firstContact.valueForKey("name") as String
        let email = firstContact.valueForKey("email") as String

        println("\(name)")
        println("\(email)")
    }

Update2:
-----------

This kind of problem occurs when entity instances didn't get loaded using your NSManagedObject class. There are a few different reasons why that happens, all of which focus on "Core Data couldn't find the class you specified for that entity on the class line in the data model."

Among the possibilities:
- You specified the wrong package for your Swift class
- You forgot to specify the class
- You misspelled the name

In my case was I forgot to specify the class as POB shows in her answer.

Sebastian
  • 6,154
  • 5
  • 33
  • 51
  • Why did you set the `-execute:` method that performs a `NSFetchRequest` inside your `NSManagedObject`subclass? – Imanou Petit Sep 17 '14 at 21:14
  • I did it for the matter of simplicity. An easy way to show the problem here. – Sebastian Sep 17 '14 at 21:25
  • Did you try using `let contact = NSEntityDescription.insertNewObjectForEntityForName("Contact", inManagedObjectContext: context) as Contact` instead of `let contact = Contact(entity: entityDescripition!, insertIntoManagedObjectContext: context)`? – Imanou Petit Sep 17 '14 at 22:14
  • I guess the problem is in executeFetchRequest. On Objective-c the return type of executeFetchRequest is a NSArray. Now on Swift the return type is a [AnyObject?]. – Sebastian Sep 18 '14 at 13:08
  • Replace `println("/...` with `println("\...` . – Imanou Petit Sep 18 '14 at 13:30
  • By using Xcode 6, I created a new Core Data Master Detail template project and added a `NSManagedObject` subClass for the `Event` entity. Then, I added your `-execute:` method in the subClass (replacing all `Contact` refs with `Event`) and it worked when I called `Event.execute()` in the `-viewDidiLoad:` of `MasterViewController`. – Imanou Petit Sep 18 '14 at 13:35

5 Answers5

34

I was able to reproduce your error message in the console. You get this message because you didn't set correctly your entity class name in the Core Data Model Editor (see image below).

enter image description here

Once done, you will be able to use your original code with Contact subClass. You can learn more about Core Data and namespaces here.

Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
6

In my case, i changed the Module as "Current Product Module" inside Core Data Model Editor.It started working fine for me.

enter image description here

Danboz
  • 561
  • 1
  • 5
  • 14
1

Check the class and module in Entity from Data Model Inspector and set the class name as entity name and module as 'Current Product Module' Class name and Module

Subhash
  • 545
  • 7
  • 11
0

I think its bad idea to set prefix of your target name like this Because if you would like to move your model into other app, or change targer name you will end up with changing it again,

So there is another way. If you look at how xcode generates core data entities now, as @A_man said you need to set current module in editor and use @objc() like this :

import CoreData

@objc(Contact)
class Contact: NSManagedObject {
    @NSManaged var name: String?
    @NSManaged var email: String?
}

And field has to be optional because they can be nil

Community
  • 1
  • 1
Serg Dort
  • 477
  • 2
  • 5
-1

I think your problem is that executeFetchRequest gives back an optional array, not an array. You need to unwrap it.

if let result: [Contact]? = context.executeFetchRequest(fetch, error: nil) as? [Contact] {

    let firstContact = result[0]

    println("/(firstContact.name)")
    println("/(firstContact.email)")
}
Surrey
  • 1
  • Thanks for the answer Surrey! It was no working with Contact, but If I use NSManageObject instead of Contact it runs. Don't ask me why ! :) – Sebastian Sep 18 '14 at 14:10