106 votes

Comment faire pour appliquer le type de NSFetchRequest exemple?

Dans Swift 2 le code suivant a été de travail:

let request = NSFetchRequest(entityName: String)

mais dans Swift 3, il donne une erreur:

Paramètre générique "ResultType" ne peut pas être déduit

parce qu' NSFetchRequest est maintenant un type générique. Dans ses documents, a écrit ceci:

let request: NSFetchRequest<Animal> = Animal.fetchRequest

donc, si mon résultat de la classe est, par exemple, Level comment dois-je me demande correctement?

Parce que cela ne fonctionne pas:

let request: NSFetchRequest<Level> = Level.fetchRequest

138voto

Sulthan Points 23360
let request: NSFetchRequest<NSFetchRequestResult> = Level.fetchRequest()

ou

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

selon la version que vous voulez.

Vous devez spécifier le type générique parce que sinon, l'appel de méthode est ambigu.

La première version est définie pour NSManagedObject, la deuxième version est généré automatiquement pour chaque objet à l'aide d'une extension, de l'e.g:

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

    @NSManaged var timeStamp: NSDate?
}

Toute la question est de supprimer l'utilisation de constantes de Chaîne.

56voto

Deniss Points 1025

Je pense que j'ai eu de travail en faisant ceci:

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

au moins, il enregistre et charge les données à partir de la Base de données.

Mais il se sent comme il n'est pas une bonne solution, mais il fonctionne pour l'instant.

33voto

Ron Diel Points 974

La structure la plus simple que j'ai trouvé qui fonctionne dans la version 3.0 est comme suit:

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

lorsque les données le Type d'entité est le Pays.

Lorsque vous essayez de créer une Base de Données BatchDeleteRequest, cependant, j'ai trouvé que cette définition ne fonctionne pas et il semble que vous aurez besoin d'aller avec la forme:

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

même si le ManagedObject et FetchRequestResult formats sont censés être équivalents.

15voto

iphaaw Points 428

Voici quelques génériques CoreData les méthodes qui pourraient répondre à votre question:

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

En supposant qu'il existe un NSManagedObject configuration de Contact comme ceci:

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

Ces méthodes peuvent être utilisées de la façon suivante:

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

6voto

letanthang Points 187

C'est la façon la plus simple de migrer vers Swift 3.0, il suffit d'ajouter <Country>

(testé et de travail)

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X