Максимальная длина атрибута String в объекте Core Data с использованием NSSortDescriptor - PullRequest
0 голосов
/ 30 апреля 2020

Я хочу найти слово с максимальным количеством символов атрибута сущности. Я пытаюсь создать дескриптор сортировки для сравнения длин строк. Код компилируется, но я получаю ошибку unsupported NSSortDescriptor selector: comparatorOfStringLengths при выполнении запроса на выборку. Я попробовал версию блока компаратора NSSortDescriptor, но она не поддерживается.

            query.sortDescriptors = [
                NSSortDescriptor.init(key: "word", ascending: false, selector: #selector(NSString.comparatorOfStringLengths))
            ]

Ниже приведена последняя версия сигнатуры метода сравнения. Я также попытался использовать static fun c с двумя аргументами, и с Any вместо String я получаю тот же результат. Я смоделировал эту подпись на стандартном веселье func localizedStandardCompare(_ string: String) -> ComparisonResult c.

extension NSString {   
    @objc func comparatorOfStringLengths(_ b: String) -> ComparisonResult {
        if self.length < b.length {
            return .orderedAscending
        }
        if self.length > b.length {
            return .orderedDescending
        }
        return .orderedSame
    }
}

Снимок экрана ошибки: enter image description here

РЕДАКТИРОВАТЬ: Я настроил / исправил подпись спецификатора селектора, но это также не удается: #selector(NSString.comparatorOfStringLengths(_:)))

1 Ответ

2 голосов
/ 30 апреля 2020

Я могу ошибаться в этом, но я думаю, что с Core Data (iOS 13) такие NSPredicate и NSSortDescriptor, как вам хотелось бы, по-прежнему невозможны.

Опция может быть добавить дополнительный атрибут wordlen типа номера, который содержит длину word. И извлеките сущность с наибольшим значением для wordlen.

. Для дальнейшего объяснения я быстро переключаюсь на мой пример стандартов Person с сущностью Person со строковым атрибутом name ( соответствует word в OP) и целочисленному атрибуту namelen.

С новой функцией validateNamelen, которая будет размещена там, где был сгенерирован код Person:

extension Person {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Person> {
        return NSFetchRequest<Person>(entityName: "Person")
    }

    @NSManaged public var name: String?
    @NSManaged public var namelen: NSNumber?

    @objc func validateNamelen(_ ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?>) throws {
        ioValue.pointee = NSNumber.init(integerLiteral: name!.count)
    }

}

это будет вызвано Core Data и поможет синхронизировать значение namelen с вновь созданными или обновленными Person сущностями.

Затем добавление индекса NameLenIndex в namelen ускоряет выборку:

enter image description here

Swift 5 Код для оценки:

    // Create Persons
    var personObj: Person = Person(context: mainContext)
    personObj.name = "Person1 A"
    personObj = Person(context: mainContext)
    personObj.name = "Person2 BB"
    personObj = Person(context: mainContext)
    personObj.name = "Person3 CCC"
    personObj = Person(context: mainContext)
    personObj.name = "Person4 A"
    personObj = Person(context: mainContext)
    personObj.name = "Person5 BB"
    personObj = Person(context: mainContext)
    personObj.name = "Person6 CCC"
    saveContext()

    // Get person
    let request: NSFetchRequest<Person> = Person.fetchRequest()

    // Which persons?
    let predicateMax = NSPredicate(format: "namelen==max(namelen)")
    let predicateMin = NSPredicate(format: "namelen==min(namelen)")

    // Persons with longest names
    request.predicate = predicateMin;

    print("Persons with shortes Names:")
    do {
        let results = try mainContext.fetch(request)
        for result in results {
            print(result.name ?? "No name found")
        }
    } catch {
        print("Error: \(error)")
    }

    request.predicate = predicateMax;

    print("Persons with longest Names:")
    do {
        let results = try mainContext.fetch(request)
        for result in results {
            print(result.name ?? "No name found")
        }
    } catch {
        print("Error: \(error)")
    }

Учитывая пустую базу данных в начале вывод выглядит так:

Persons with shortes Names:
Person1 A
Person4 A
Persons with longest Names:
Person6 CCC
Person3 CCC
...