We ended up with subclass (Swift 4). Idea behind - pass type as argument. Rest of setup operates NSManagedObject
type in order to work around compile errors.
public class FetchedResultsController<T: NSManagedObject>: NSFetchedResultsController<NSManagedObject> {
public convenience init(fetchRequest: NSFetchRequest<NSManagedObject>, context: NSManagedObjectContext, _: T.Type) {
self.init(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
}
public var numberOfSections: Int {
return sections?.count ?? 0
}
public var numberOfFetchedEntities: Int {
return fetchedObjects?.count ?? 0
}
public func entity(at indexPath: IndexPath) -> T {
if let value = object(at: indexPath) as? T {
return value
} else {
fatalError()
}
}
public func entity(at row: Int) -> T {
let ip = IndexPath(item: row, section: 0)
return entity(at: ip)
}
public var fetchedEntities: [T] {
let result = (fetchedObjects ?? []).compactMap { $0 as? T }
return result
}
}
Extensions:
extension Requests {
public static func all<T: NSManagedObject>(_: T.Type) -> NSFetchRequest<NSManagedObject> {
let request = NSFetchRequest<NSManagedObject>(entityName: T.entityName)
return request
}
public static func ordered<T: NSManagedObject>(by: String, ascending: Bool, _: T.Type) -> NSFetchRequest<NSManagedObject> {
let request = NSFetchRequest<NSManagedObject>(entityName: T.entityName)
request.sortDescriptors = [NSSortDescriptor(key: by, ascending: ascending)]
return request
}
}
extension NSManagedObject {
public static var entityName: String {
let className = NSStringFromClass(self) // As alternative can be used `self.description()` or `String(describing: self)`
let entityName = className.components(separatedBy: ".").last!
return entityName
}
public static var entityClassName: String {
let className = NSStringFromClass(self)
return className
}
}
Usage:
extension ParentChildRelationshipsMainController {
private func setupFetchedResultsController() -> FetchedResultsController<IssueList> {
let request = DB.Requests.ordered(by: #keyPath(IssueList.title), ascending: true, IssueList.self)
let result = FetchedResultsController(fetchRequest: request, context: PCDBStack.shared.mainContext, IssueList.self)
return result
}
}
extension ParentChildRelationshipsMainController: NSTableViewDataSource, NSTableViewDelegate {
func numberOfRows(in tableView: NSTableView) -> Int {
return frController.numberOfFetchedEntities
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let rowID = NSUserInterfaceItemIdentifier("rid:generic")
let item = frController.entity(at: row)
// ...
}
}