How to write an extension for NSFetchedResultsController in Swift 4

前端 未结 3 1317
有刺的猬
有刺的猬 2021-01-12 05:45

I\'m trying to write a simple extension to the NSFetchedResultsController class in Swift 4.

Here\'s my first attempt - which worked in Swift 3:

相关标签:
3条回答
  • 2021-01-12 05:59

    I think I found the answer to this one. The function needs to be available to Objective-C.

    Adding @objc to the func should remove the compile error. At least it did for me!

    0 讨论(0)
  • 2021-01-12 06:11

    Subclass-ing is not good, composition is a better way to go. Here is my take on this:

    public protocol FetchedDataProtocol {
        associatedtype T: NSFetchRequestResult
        var controller: NSFetchedResultsController<T> { get }
        subscript(_ indexPath: IndexPath) -> T { get }
    }
    

    Doing it this way you avoid casting and mapping:

    public extension FetchedDataProtocol {
        subscript(_ indexPath: IndexPath) -> T {
            return controller.object(at: indexPath)
        }
    }
    

    And then you use it as your own class that has subscript (and whatever you want):

    public struct MainFetchedData<T: NSFetchRequestResult>: FetchedDataProtocol {
        public let controller: NSFetchedResultsController<T>
        public init(_ controller: NSFetchedResultsController<T>) {
            self.controller = controller
        }
    }
    
    0 讨论(0)
  • 2021-01-12 06:13

    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)
          // ...
       }
    }
    
    0 讨论(0)
提交回复
热议问题