Multiple NSFetchedResultsControllers in Swift 3

I have a class in Swift that wraps multiple NSFetchedResultsControllers, becomes their delegate, and converts IndexPaths before returning its own delegate to it. This class can accept NSFetchedResultsControllers that return different objects if they conform to the same protocol. When upgrading to Swift 3, I cannot get the same functionality to compile.

Let's say I want to wrap two NSFetchedResultsControllers, returning two different Entity types that will be displayed in the same tableView. Both CoreData objects comply with the following protocol

protocol ManagedObjectDisplayType : NSFetchRequestResult {
    var id:String { get }
    func friendlyName() -> String
}

The problem is that now NSFetchedResultsControllers are common, there is no specific type of NSFetchedResultsController that I can pass to my Wrapper class, because the two controllers are of different types.

For instance:

 let entity1Request = NSFetchRequest<Entity1>(entityName: entityName)
 let entity1Frc = NSFetchedResultsController<ManagedObjectDisplayType>(fetchRequest: entity1Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
 let entity2Request = NSFetchRequest<Entity2>(entityName: entityName)
 let entity2Frc = NSFetchedResultsController<ManagedObjectDisplayType>(fetchRequest: entity2Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

When I do this, I get the following error: "Using" ManagedObjectDisplayType "as a specific type that conforms to the" NSFetchRequestResult "protocol is not supported," which makes full sense.

But I'm not sure of another way of doing what I'm trying to do.

+4
source share
2 answers

It looks like work for ...

enter image description here

Type Erasure!

Swift , . , , NSFetchedResultsController . , Swift ( ) , . , . AnyFetchedResultsController (a NSFetchedResultsController<T> where T: ManagedObjectDisplayType), .

class AnyFetchedResultsController: CustomDebugStringConvertible
{
    var descImpl: () -> String
    var performImpl: () throws -> ()

    init<T>(_ controller: NSFetchedResultsController<T>) where T: ManagedObjectDisplayType {    
        descImpl = { controller.debugDescription }
        performImpl = { try controller.performFetch() }
    }

    func performFetch() throws {
        try performImpl()
    }

    var debugDescription: String {
        return "wrapping \(descImpl())"
    }
}

let entity1Request = NSFetchRequest<Entity1>(entityName: "Foobar")
let entity1Frc = NSFetchedResultsController<Entity1>(fetchRequest: entity1Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
let entity2Request = NSFetchRequest<Entity2>(entityName: "Barfoo")
let entity2Frc = NSFetchedResultsController<Entity2>(fetchRequest: entity2Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)


let frcs: [AnyFetchedResultsController] = [AnyFetchedResultsController(entity1Frc), AnyFetchedResultsController(entity2Frc)]

, , AnyFetchedResultsController , NSFetchedResultsController.

, . , , !

AnyFetchedResultsController.init:

init<T, U: NSFetchedResultsController<T>>(_ controller: U, _ managedObjectType: T? = nil) where T: ManagedObjectDisplayType

dummy managedObjectType, , , . , :

init<T>(_ controller: NSFetchedResultsController<T>) where T: ManagedObjectDisplayType

( ), , .

+3

ManagedObjectDisplayType

, Entity1 :

class Entity1 : NSManagedObject, ManagedObjectDisplayType {
    var id:String {
        return "42"
    }

    func friendlyName() -> String {
        return "foobar"
    }

}

 let entity1Request = NSFetchRequest<Entity1>(entityName: entityName)
 let entity1Frc = NSFetchedResultsController<ManagedObjectDisplayType>(fetchRequest: entity1Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

 let entity1Request = NSFetchRequest<Entity1>(entityName: entityName)
 let entity1Frc = NSFetchedResultsController<Entity1>(fetchRequest: entity1Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

, , .

+2

Source: https://habr.com/ru/post/1659542/


All Articles