2014-09-17 7 views
13

jestem testowania Swift z CoreData i stworzyłem następujący kod:executeFetchRequest rzut błąd krytyczny: Element NSArray udało się dopasować Swift Array typ elementu

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 = "[email protected]" 

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

    } 

} 

Kiedy biegnę:

Contact.execute() 

Następnie kompilator rzuci ten błąd:

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

kiedy próbuję uzyskać wartości z tablicy:

let firstContact = result[0] as Contact 

Zgaduję, że problem występuje w executeFetchRequest. Na Objective-c typem zwrotu executeFetchRequest jest NSArray. Teraz na Swift typem zwrotu jest [AnyObject]?.

Próbowałem rzucić wynik [AnyObject]? do NSArray, ale Xcode powiedział:

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

Co robię źle?

Używam: Xcode 6.0 (6A313) GM i OSX 10.9.4

Aktualizacja:
-----------

Jeśli Otrzymuję executeFetchRequest wynik jako opcjonalna tablica i używam [NSManagedObject] zamiast [Contact] to działa.

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:
-----------

Tego rodzaju problem występuje, gdy instancje jednostka nie ładowane przy użyciu klasę NSManagedObject. Istnieje kilka różnych powodów, dla których tak się dzieje, a wszystkie koncentrują się na tym, że "Dane podstawowe nie mogą znaleźć klasy określonej dla tej jednostki na linii klasy w modelu danych".

Wśród możliwości:
- Podałeś niewłaściwy pakiet dla Swift klasy
- Zapomniałaś, aby określić klasę
- literówka nazwę

W moim przypadku był zapomniałem określić klasę jak pokazuje POB w swojej odpowiedzi.

+0

Dlaczego ustawić '' -execute: metoda, która wykonuje a 'NSFetchRequest' w twojej klasie' NSManagedObject'subclass? –

+0

Zrobiłem to dla prostoty. Łatwy sposób na pokazanie problemu tutaj. – Sebastian

+0

Czy próbowałeś użyć 'let contact = NSEntityDescription.insertNewObjectForEntityForName (" Contact ", inManagedObjectContext: context) jako Contact' zamiast 'let contact = Contact (entity: entityDescripition !, insertIntoManagedObjectContext: context)'? –

Odpowiedz

32

Udało mi się odtworzyć komunikat o błędzie na konsoli. Otrzymujesz tę wiadomość, ponieważ nie ustawiłeś poprawnie nazwy klasy encji w Edytorze modelu danych podstawowych (patrz obrazek poniżej).

enter image description here

Gdy to zrobisz, będziesz mógł korzystać z oryginalnego kodu z Contact podklasy. Możesz dowiedzieć się więcej o Core Data i przestrzeniach nazw here.

+1

Działa jak urok! Wielkie dzięki! :) – Sebastian

+0

ratownik! ... –

+0

w tym polu klasy, nie mogę dodać "." –

0

Myślę, że twój problem polega na tym, że executeFetchRequest zwraca opcjonalną tablicę, a nie tablicę. Musisz go rozpakować.

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

    let firstContact = result[0] 

    println("/(firstContact.name)") 
    println("/(firstContact.email)") 
} 
+0

Dzięki za odpowiedź Surrey! To nie działało z Kontaktem, ale jeśli używam NSManageObject zamiast Contact działa, nie pytaj mnie dlaczego! :) – Sebastian

3

W moim przypadku zmieniłem moduł jako "Moduł bieżącego produktu" w edytorze Core Data Model Editor. Zaczęło działać dobrze dla mnie. enter image description here

0

myślę, że jego zły pomysł, aby ustawić prefiks nazwy docelowej jak this Bo jeśli chcesz przenieść swój model do innej aplikacji lub zmienić nazwę targer skończy się ze zmieniającymi się go ponownie,

Jest więc inny sposób. Jeśli spojrzeć na to, jak Xcode generuje jednostki podstawowe dane teraz, jak @A_man że trzeba ustawić moduł obecną w edytorze i korzystać @objc() tak:

import CoreData 

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

i pole musi być opcjonalne, ponieważ mogą one być nil

0

Sprawdź klasę i moduł w Entity Data model z Inspektorem i ustawić nazwę klasy jako nazwy podmiotu oraz modułu jako „Aktualny produkt moduł” Class name and Module