Изменить поведение сортировки nil при использовании @FetchRequest с Базовыми данными в SwiftUI - PullRequest
1 голос
/ 23 февраля 2020

Я выбираю сущности из Core Data в SwiftUI и хотел бы отсортировать их так:

  1. Если есть следующая дата, сортируйте их по возрастанию
  2. Под теми, у которых есть по следующей дате отсортировать оставшиеся по дате создания

У меня есть:

@FetchRequest(entity: MyEntity.entity(), sortDescriptors: [
    NSSortDescriptor(keyPath: \MyEntity.nextDate, ascending: true),
    NSSortDescriptor(keyPath: \MyEntity.dateCreated, ascending: true)
]) private var entities: FetchedResults<MyEntity>

Проблема в том, что те, у которых нет следующей даты, все сортируются выше тех, которые имеют следующая дата не равна нулю, как видно из этого другого вопроса .

Я пытался создать подкласс NSSortDescriptor, чтобы переместить nil значения в конец, но он никогда не вызывает ни одного из переопределенные функции.

final class NilsLastSortDescriptor: NSSortDescriptor {
    override func copy(with zone: NSZone? = nil) -> Any {
        return NilsLastSortDescriptor(key: self.key, ascending: self.ascending, selector: self.selector)
    }

    override var reversedSortDescriptor: Any {
        return NilsLastSortDescriptor(key: self.key, ascending: !self.ascending, selector: self.selector)
    }

    override func compare(_ object1: Any, to object2: Any) -> ComparisonResult {
        if (object1 as AnyObject).value(forKey: self.key!) == nil && (object2 as AnyObject).value(forKey: self.key!) == nil {
            return .orderedSame
        }
        if (object1 as AnyObject).value(forKey: self.key!) == nil {
            return .orderedDescending
        }
        if (object2 as AnyObject).value(forKey: self.key!) == nil {
            return .orderedAscending
        }
        return super.compare(object1, to: object2)
    }
}

Я также пытался использовать NSSortDescriptor API, который включает в себя блок компаратора, однако это происходит сбой с

Исключение: «неподдерживаемый NSSortDescriptor (блоки компаратора не поддерживается) "

Как можно добиться желаемого поведения сортировки?

Ответы [ 2 ]

0 голосов
/ 24 февраля 2020

@FetchRequest использует дескриптор сортировки как часть запроса выборки, и, следовательно, вы не можете использовать блоки компаратора в определении запроса выборки (по крайней мере, не с хранилищем SQLite). Однако вы можете отсортировать результаты выборки (entities) как часть обработки body представления, используя сортировку (по:) :

var body: some View {
        VStack {
        List{
            ForEach(self.entities.sorted(by: { first, second in
                if first.nextDate == nil && second.nextDate == nil { return (first.dateCreated <= second.dateCreated) }
                if first.nextDate == nil { return false }
                if second.nextDate == nil { return true }
                if first.nextDate! == second.nextDate! { return (first.dateCreated <= second.dateCreated) }
                return (first.nextDate! < second.nextDate!)
            }), id: \.self) { myEntity in
                // Your code for your cells...
                ...
            }
        }
    }
}

Для простоты я предположил, что dateCreated не является обязательным. Если нет, вам нужно будет изменить предикат для сортировки, чтобы обрабатывать нулевые значения. Возможно, это можно было бы написать и более красиво, но я надеюсь, что вы поняли идею.

Просто отметьте, что это сортировка в памяти, так что нет представления о влиянии производительности и / или памяти этого решения.

0 голосов
/ 24 февраля 2020

В CoreData сортировка выполняется только с использованием метода из класса NSString, например «сравнить:» или «локализованныйСтандарт: сравнение», что-то вроде этого.

Поскольку вы не можете переопределить эти методы или даже изменить их в большинстве случаев, вы можете рассмотреть другие обходные пути.

Вместо даты «Ноль» вы можете установить Special Date, что очень поздно, если желаемыми данными являются «Ноль». Таким образом, вы можете отсортировать эти даты в нижней части. Вы не можете отображать эти специальные даты или отображать их как «ноль» в SwiftView.

Вы можете просто играть в игру NSString, а не subclass

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...