Search code examples
iosswiftcore-datansfetchedresultscontroller

Creating a Key Path from a computed var in Swift 4


I have a fetchedResultsController where I'd like to add a keypath for Date so I don't have a section for every second of the day. Simple enough, I thought...I'll create an extension for MyEntity

extension MyEntity {

  var dateForSection: String {
    get {
      let dateFormatter = DateFormatter()
      dateFormatter.dateStyle = .long
      if let time = self.time {
        return dateFormatter.string(from: time)
      }
      return "Unavailable Date"
    }
  }
}

Then, on MyViewController in the fetchedResultsController lazy var declaration, I declare the frc as follows:

let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: #keyPath(MyEntity.dateForSection), cacheName: nil)

I get this compiler error:

Argument of '#keyPath' refers to non-'@objc' property 'dateForSection'

In Googling the issue saw some Swift bug reports from 2016, but I haven't seen any solutions to this. How would I get around this?

Addendum

I've tried adding @objc in front of the var declaration. I've also tried adding @objc dynamic, closing Xcode, nuking derived data from the command line, rebooting Xcode, rebooting my machine, etc.


Solution

  • I can't reproduce the problem. I whipped out a Core Data project with a Group class auto-generated from my entity, and added a computed variable:

    extension Group {
        @objc var yoho : String {
            return "yoho"
        }
    }
    

    Then I modified that same line in my lazy fetched results controller initializer:

        let frc = NSFetchedResultsController(
            fetchRequest:req,
            managedObjectContext:self.managedObjectContext,
            sectionNameKeyPath:#keyPath(Group.yoho), cacheName:nil)
    

    It compiles. I don't know why yours doesn't.

    On the other hand, a #keyPath is nothing but a string generated for you, and what's expected here is a string, so if you really can't get it to compile, just put "dateForSection" and be done with it. Of course that doesn't mean it will run without crashing, but at least it will compile and you can move on.