Shane
Shane

Reputation: 397

swift 3 - pass entity as argument to function

In an earlier version of swift, I had a core data function

func retrieveItemsForRelatedEntity(entity: String, relatedEntity: String, identifier: String, sortDescriptors: [NSSortDescriptor]?) -> Array<AnyObject>? {

    let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let context: NSManagedObjectContext = appDel.managedObjectContext!
    let frequest = NSFetchRequest(entityName: entity)
    frequest.returnsObjectsAsFaults = false

    if sortDescriptors != nil {
        frequest.sortDescriptors = sortDescriptors
    } 

    switch relatedEntity {
    case "CostCentre":
        frequest.predicate = NSPredicate(format: "costCentre.identifier == '\(identifier)'")
        return try! context.executeFetchRequest(frequest)
    case "CostCentreDay":
        frequest.predicate = NSPredicate(format: "costCentreDay.identifier == '\(identifier)'")
        return try! context.executeFetchRequest(frequest)
    case "Resource":
        frequest.predicate = NSPredicate(format: "resource.identifier == '\(identifier)'")
        return try! context.executeFetchRequest(frequest)
    case "ResourceDay":
        frequest.predicate = NSPredicate(format: "resourceDay.identifier == '\(identifier)'")
        return try! context.executeFetchRequest(frequest)
    case "CostedDay":
        frequest.predicate = NSPredicate(format: "costedDay.identifier == '\(identifier)'")
        return try! context.executeFetchRequest(frequest)
    default:
        print("wrong entity for this function")
        return nil
    }
}

With Swift 3.0, the "Generic Result Type cannot be inferred", so instead of passing in the entity title Strings, can I pass in the entity Type, and switch on that for my fetch request?

Upvotes: 1

Views: 1285

Answers (3)

nadi9
nadi9

Reputation: 576

please try this. It helped me.

func retrieveItemsForRelatedEntity(entity: String, relatedEntity: NSEntityDescription, identifier: String, sortDescriptors: [NSSortDescriptor]?) -> Array<AnyObject>? {

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext

    let frequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity) 

and

switch relatedEntity {
    case NSEntityDescription.entity(forEntityName: "CostCentre", in: context)!:

Upvotes: 2

Daniel Oram
Daniel Oram

Reputation: 8411

To answer your question

so instead of passing in the entity title Strings, can I pass in the entity Type, and switch on that for my fetch request?

Yes, that would be the best approach. Something like

 retrieveItemsForRelatedEntity(entity: NSManagedObject, relatedEntity: String, identifier: String, sortDescriptors: [NSSortDescriptor]?) -> Array<AnyObject>? {

From another question

You have to specify the generic type because otherwise the method call is ambiguous.

The first version is defined for NSManagedObject, the second version is generated automatically for every object using an extension, e.g:

This extension is automatically generated (as can be seen below with the Animal type.

From Apple's Documentation on changes from Swift 2 to Swift 3

NSFetchRequest is now a parameterized type based on a new NSFetchRequestResult protocol.

The function name for executeFetchRequest(...) also changed in Swift 3

public func fetch<T : NSFetchRequestResult>(_ request: NSFetchRequest<T>) throws -> [T]

Apple Documentation example of changes to NSFetchRequest

Swift 2

func findAnimals() {
    let request = NSFetchRequest(entityName:”Animal")
    do {
        guard let searchResults = try context.executeFetchRequest(request) as? [Animal] else {
            print("Results were not of the expected structure")
        }
        ... use(searchResults) ...
    } catch {
    print("Error ocurred during execution: \(error)")
}

}

Swift 3

func findAnimals() {
    let request: NSFetchRequest<Animal> = Animal.fetchRequest
    do {
        let searchResults = try context.fetch(request)
        ... use(searchResults) ...
    } catch {
        print("Error with request: \(error)")
    }
}

So converting your code in Swift 2 for creating NSFetchRequest

let frequest = NSFetchRequest(entityName: entity)

to Swift 3

let frequest: NSFetchRequest<YourEntityType> = YourEntityType.fetchRequest()

and

context.executeFetchRequest(frequest)

will be

context.fetch(frequest)

Note: From other examples across the web the Apple docs code example of Animal.fetchRequest may be wrong and instead should be Animal.fetchRequest()

Upvotes: 2

Ajil O.
Ajil O.

Reputation: 6892

Try this :

let frequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity)

Upvotes: 1

Related Questions