NSTableView сортировка десятичного столбца вызывает исключение - PullRequest
0 голосов
/ 22 февраля 2019

У меня есть NSTableView, который я использую для экспериментов с сортировкой столбцов.Столбцы строки, целого числа и даты, кажется, работают нормально, но десятичный столбец вызывает сбой, над которым я почесал голову.

Вот структура данных:

class LearningStruct : NSObject, Decodable {
    @objc var ID : Int
    @objc var Text : String
    @objc var Description : String
    @objc var CreationDate : Date
    @objc var UpdateDateTime : Date?
    @objc var ValueX: Decimal
    @objc var IsTrue : Bool
}

(обратите внимание на использование @objc и NSObject, очевидно, Swift не может обрабатывать кодирование значения ключа, необходимое для сортировки)

Я создаю некоторые тестовые данные JSON:

let learningJSON = "{\"Items\": [{\"ID\": 1, \"Text\": \"Item 1 text\", \"Description\": \"This is item 1 description\", \"CreationDate\": \"02/17/2019\", \"ValueX\": 123.45, \"UpdateDate\": \"02/17/2019\", \"IsTrue\": true}, {\"ID\": 2, \"Text\": \"Item 2 text\", \"Description\": \"This is item 2 description\", \"CreationDate\": \"02/14/2019\", \"ValueX\": 789.01, \"UpdateDate\": \"02/14/2019\", \"IsTrue\": false}]}"
internal var learningItems = [LearningStruct]()

Затем я использую декодер для заполнения массива:

            let decoder = JSONDecoder()
            let dateformatter = DateFormatter()
            dateformatter.dateFormat = "MM/dd/yyyy" // "MM/dd/yyyy'T'HH:mm:ss"
            decoder.dateDecodingStrategy = .formatted(dateformatter)
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            let learningData = try decoder.decode(LearningItems.self, from: learningJSON.data(using: .utf8)!) as LearningItems
            learningItems = learningData.Items

У идентификатора NSTableColumns для имени свойства в раскадровке установлено значение для имени свойстваmapping.

           for prop in properties {
                let colindex = learningTableView.column(withIdentifier: NSUserInterfaceItemIdentifier.init(prop)) // Get the column index number for that property key
                if (colindex >= 0) { // If the column exists
                    let descriptorID = NSSortDescriptor(key: prop, ascending: true)
                    learningTableView.tableColumns[colindex].sortDescriptorPrototype = descriptorID
                }
            }

Вот логика сортировки:

/// Sorting logic
    func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {

        print("--- Sorting logic begin ---")

        // Debug print the sorters
        for col in learningTableView.tableColumns {

            if col.sortDescriptorPrototype != nil {
                let sorter = col.sortDescriptorPrototype!.key!
                let direction = col.sortDescriptorPrototype!.ascending
                print("Column \(col.identifier.rawValue): sort descriptor: \(sorter), is ascending: \(direction)")
            } else {
                print("Column \(col.identifier.rawValue): no sort descriptor")
            }
        }

        print("+++ Sort descriptors list")
        let learningItemsMutable = NSMutableArray(array: learningItems)
        let sorters = tableView.sortDescriptors
        for sortdesc in sorters {
            print("Sort descriptor: \(sortdesc.key!)")
        }
        print("Sorting...")
        learningItemsMutable.sort(using: sorters)
        learningItems = learningItemsMutable as! [LearningStruct]
        tableView.reloadData()
        print("--- Sorting logic end ---")
    }

Когда я запускаю код, он отлично сортирует все, когда я нажимаю на столбец, пока не доберусь до столбца «ValueX»,В приведенном ниже примере я кликаю по каждому столбцу по порядку, заканчиваясь на «Значение X».Когда я нажимаю на это, я получаю исключение, которое на самом деле мне не поможет ... может кто-нибудь помочь?

Ответы [ 2 ]

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

Используемый тип Decimal в Objective-C NSDecimal отсутствует в списке поддерживаемых типов кодирования значения ключа. Документация KVC

typedef struct {
    signed   int _exponent:8;
    unsigned int _length:4;     // length == 0 && isNegative -> NaN
    unsigned int _isNegative:1;
    unsigned int _isCompact:1;
    unsigned int _reserved:18;
    unsigned short _mantissa[NSDecimalMaxSize];
} NSDecimal;

NSDecimal использует битовые поля, которые являются ключевым вопросом.

Каждая попытка заставить его работать (это должно быть возможно) будетНе кодируется из коробки.

0 голосов
/ 22 февраля 2019

Может быть какая-то проблема с тем, как Decimal соединен с NSDecimalNumber

Попробуйте использовать NSDecimalNumber в вашем классе LearningStruct, чтобы увидеть, что сбой все еще существует.

В качестве альтернативы создайте новое свойство только для чтения и используйте его для сортировки:

class LearningStruct: NSObject, Decodable {
    @objc var ID: Int
    @objc var Text: String
    @objc var Description: String
    @objc var CreationDate: Date
    @objc var UpdateDateTime: Date?
    @objc var ValueX: Decimal
    @objc var IsTrue: Bool

    @objc var ValueXNumber: NSDecimalNumber {
        return ValueX as NSDecimalNumber
    }
}

Соответствующие примечания: переменные экземпляра обычно называются в Swift первой строчной буквой.И @objc требуется, потому что NSSortDescriptor является классом Objective-C, и в противном случае он не увидит свойства вашего класса Swift.

...