webentwicklung-frage-antwort-db.com.de

Wie wende ich den Typ auf eine NSFetchRequest-Instanz an?

In Swift 2 hat der folgende Code funktioniert:

let request = NSFetchRequest(entityName: String)

aber in Swift 3 gibt es Fehler:

Der generische Parameter "ResultType" konnte nicht abgeleitet werden

weil NSFetchRequest jetzt ein generischer Typ ist. In ihren Dokumenten haben sie Folgendes geschrieben:

let request: NSFetchRequest<Animal> = Animal.fetchRequest

wenn also meine Ergebnisklasse Level ist, wie sollte ich sie korrekt anfordern?

Weil das nicht funktioniert:

let request: NSFetchRequest<Level> = Level.fetchRequest
94
Deniss
let request: NSFetchRequest<NSFetchRequestResult> = Level.fetchRequest()

oder

let request: NSFetchRequest<Level> = Level.fetchRequest()

je nachdem welche Version Sie möchten.

Sie müssen den generischen Typ angeben, da der Methodenaufruf sonst mehrdeutig ist.

Die erste Version ist für NSManagedObject definiert, die zweite Version wird automatisch für jedes Objekt mithilfe einer Erweiterung generiert, z.

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

    @NSManaged var timeStamp: NSDate?
}

Der springende Punkt ist, die Verwendung von String-Konstanten zu entfernen.

126
Sulthan

Ich glaube, ich habe es so zum Laufen gebracht:

let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Level")

zumindest speichert und lädt er Daten aus der Datenbank.

Aber es fühlt sich an, als sei es keine richtige Lösung, aber es funktioniert im Moment.

53
Deniss

Die einfachste Struktur, die ich in 3.0 gefunden habe, sieht folgendermaßen aus:

let request = NSFetchRequest<Country>(entityName: "Country")

wobei der Datenentitätstyp Land ist. 

Beim Versuch, ein Core Data BatchDeleteRequest zu erstellen, habe ich jedoch festgestellt, dass diese Definition nicht funktioniert und es scheint, dass Sie das Formular verwenden müssen:

let request: NSFetchRequest<NSFetchRequestResult> = Country.fetchRequest()

obwohl die Formate ManagedObject und FetchRequestResult gleichwertig sein sollen.

33
Ron Diel

Hier einige generische CoreData-Methoden, die Ihre Frage beantworten könnten:

import Foundation
import Cocoa

func addRecord<T: NSManagedObject>(_ type : T.Type) -> T
{
    let entityName = T.description()
    let context = app.managedObjectContext
    let entity = NSEntityDescription.entity(forEntityName: entityName, in: context)
    let record = T(entity: entity!, insertInto: context)
    return record
}

func recordsInTable<T: NSManagedObject>(_ type : T.Type) -> Int
{
    let recs = allRecords(T.self)
    return recs.count
}


func allRecords<T: NSManagedObject>(_ type : T.Type, sort: NSSortDescriptor? = nil) -> [T]
{
    let context = app.managedObjectContext
    let request = T.fetchRequest()
    do
    {
        let results = try context.fetch(request)
        return results as! [T]
    }
    catch
    {
        print("Error with request: \(error)")
        return []
    }
}

func query<T: NSManagedObject>(_ type : T.Type, search: NSPredicate?, sort: NSSortDescriptor? = nil, multiSort: [NSSortDescriptor]? = nil) -> [T]
{
    let context = app.managedObjectContext
    let request = T.fetchRequest()
    if let predicate = search
    {
        request.predicate = predicate
    }
    if let sortDescriptors = multiSort
    {
        request.sortDescriptors = sortDescriptors
    }
    else if let sortDescriptor = sort
    {
        request.sortDescriptors = [sortDescriptor]
    }

    do
    {
        let results = try context.fetch(request)
        return results as! [T]
    }
    catch
    {
        print("Error with request: \(error)")
        return []
    }
}


func deleteRecord(_ object: NSManagedObject)
{
    let context = app.managedObjectContext
    context.delete(object)
}

func deleteRecords<T: NSManagedObject>(_ type : T.Type, search: NSPredicate? = nil)
{
    let context = app.managedObjectContext

    let results = query(T.self, search: search)
    for record in results
    {
        context.delete(record)
    }
}

func saveDatabase()
{
    let context = app.managedObjectContext

    do
    {
        try context.save()
    }
    catch
    {
        print("Error saving database: \(error)")
    }
}

Angenommen, es gibt ein NSManagedObject-Setup für Kontakt wie folgt:

class Contact: NSManagedObject
{
    @NSManaged var contactNo: Int
    @NSManaged var contactName: String
}

Diese Methoden können auf folgende Weise verwendet werden:

let name = "John Appleseed"

let newContact = addRecord(Contact.self)
newContact.contactNo = 1
newContact.contactName = name

let contacts = query(Contact.self, search: NSPredicate(format: "contactName == %@", name))
for contact in contacts
{
    print ("Contact name = \(contact.contactName), no = \(contact.contactNo)")
}

deleteRecords(Contact.self, search: NSPredicate(format: "contactName == %@", name))

recs = recordsInTable(Contact.self)
print ("Contacts table has \(recs) records")

saveDatabase()
9
iphaaw

Dies ist die einfachste Möglichkeit, zu Swift 3.0 zu migrieren. Fügen Sie einfach <Country> hinzu.

(getestet und gearbeitet)

let request = NSFetchRequest<Country>(entityName: "Country")
6
letanthang

Ich hatte auch "ResultType" konnte Fehler nicht abgeleitet werden. Sie wurden gelöscht, nachdem ich das Datenmodell neu erstellt hatte, wobei der Codegen der Entitäten auf "Class Definition" gesetzt wurde. Ich habe hier eine kurze Beschreibung mit Schritt-für-Schritt-Anweisungen geschrieben:

Suche nach einem klaren Tutorial zum überarbeiteten NSPersistentContainer in Xcode 8 mit Swift 3

Mit "umgebaut" meine ich, dass ich eine neue Modelldatei mit neuen Einträgen und Attributen erstellt habe. Ein bisschen langweilig, aber es hat funktioniert!

0
Michael Garito

Ich hatte das gleiche Problem und habe es mit den folgenden Schritten gelöst:

  • Wählen Sie Ihre xcdatamodeld-Datei aus und gehen Sie zum Data Model Inspector
  • Wählen Sie Ihre erste Entität und gehen Sie zur Section-Klasse 
  • Stellen Sie sicher, dass Codegen "Class Definition" ausgewählt ist.
  • Entfernen Sie alle generierten Entity-Dateien. Du brauchst sie nicht mehr. 

Danach musste ich alle Vorkommen von fetchRequest entfernen/neu schreiben, da XCode sich irgendwie mit der codegenerierten Version zu verwechseln scheint. 

HTH

0
Oliver Koehler

Was bisher für mich am besten funktionierte, war:

let request = Level.fetchRequest() as! NSFetchRequest<Level>
0
benhofmann

Swift 3.0 Das sollte funktionieren.

let request: NSFetchRequest<NSFetchRequestResult> = NSManagedObject.fetchRequest()
request.entity = entityDescription(context)
request.predicate = predicate
0
Chamath Jeevan