Swift 3中的多个NSFetchedResultsControllers

内森·哈特

我在Swift中有一个类,它包装了多个NSFetchedResultsControllers,成为它们的委托,并在返回到其自己的委托之前转换IndexPath。此类可以使用NSFetchedResultsControllers返回不同的实体,只要它们符合相同的协议。升级到Swift 3时,我无法编译相同的功能。

假设我要包装两个NSFetchedResultsControllers,它们返回两种不同的Entity类型以显示在单个tableView中。两个CoreData实体均符合以下协议

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

问题在于,现在NSFetchedResultsControllers是通用的,没有可传递给Wrapper类的NSFetchedResultsController具体类型,因为这两个控制器的类型不同。

例如:

 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)

当我这样做时,出现以下错误:“不支持将'ManagedObjectDisplayType'作为符合协议'NSFetchRequestResult'的具体类型使用”,这是很有意义的。

但是我不确定另一种方法来做我想做的事情。

戴夫·韦斯顿

这看起来像是...的工作

在此处输入图片说明

输入擦除!

在Swift中有很多关于类型擦除的文章,但这是一个有趣的情况。我假设您在创建可以容纳多个NSFetchedResultsController不同类型对象的对象时遇到问题问题在于,Swift(当前版本)需要一种具体类型来正确分配所需的内存。标准库和其他地方对此的标准解决方案是创建一个隐藏基础类型的框。在这种情况下,AnyFetchedResultsController下面类有效地擦除NSFetchedResultsController<T> where T: ManagedObjectDisplayType它所包装的具体类型(an )。

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

非常复杂,并且有一个虚拟的managedObjectType参数,该参数似乎对于修复某些编译器错误是必需的。但是,我发现更简单了:

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

(同样在上方)似乎同样有效。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章