Can SortDescriptor work with a KeyPath to an enum represented by an Int?

In my model, I have a property category of type Category (en Enum represented by an Int16). I want to use the new SortDescriptor with the category property but the compiler complains that No exact matches in call to initializer. It's working fine with the rawCategory, or if I use a NSSortDescriptor.

Is there a way to make it work with the enum instead?

class Book: NSObject {
    var category: Category
    var rawCategory: Int16

    init(category: Category) {
        self.category = category
        self.rawCategory = category.rawValue
    }
}

enum Category: Int16 {
    case actionAdventure
    case classics
    case comic
    case detective
    case fantasy
}

func makeSortDescriptor() {
    let categorySortDescriptor = SortDescriptor(\Book.category) // No exact matches in call to initializer
    let rawCategorySortDescriptor = SortDescriptor(\Book.rawCategory)

    let categoryNSSortDescriptor = NSSortDescriptor(keyPath: \Book.category, ascending: true)
}
1 Like

Specifying the rawValue in the KeyPath works.

let categorySortDescriptor = SortDescriptor(\Book.category.rawValue)

An alternate could be to add an extension like

extension SortDescriptor where Compared: NSObject {
  init<RawRepresentable: Swift.RawRepresentable>(
    _ keyPath: KeyPath<Compared, RawRepresentable>,
    order: SortOrder = .forward
  ) where RawRepresentable.RawValue == Int16 {
    self.init(keyPath.appending(path: \.rawValue), order: order)
  }
}

But we then would have to create it for all types we want to forward to.
Ideally, it should have worked with KeyPath<Compared, some Comparable>.

You can pass .rawValue since you store Int16 or you can store Category instead of raw value, then perhaps implement Comparable for Category to make it work.

1 Like