Last active
March 6, 2023 11:38
-
-
Save Dev1an/8fa1e9258a7e362edbdd9dbee0664af0 to your computer and use it in GitHub Desktop.
Simple table data source for NSTableView
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct Person: CustomStringConvertible { | |
| var name: String | |
| var birthday: Date | |
| var friends: [Person] | |
| var description: String { return name + "(\(friends.count))" } | |
| } | |
| enum TableRow: String, NSUserInterfaceItemIdentifierConvertible { | |
| case name, birthday, age | |
| } | |
| let michel = Person(name: "Michel", birthday: Date(), friends: []) | |
| let dorothea = Person(name: "Dorothea", birthday: Date(), friends: []) | |
| let dataSource = TableDataSource<[Person]>( | |
| data: [michel, dorothea], | |
| columns: [ | |
| TableRow.name: .init(\.name), | |
| .birthday: .init(\.birthday), | |
| .age: .init(\.birthday) { -$0.timeIntervalSinceNow } | |
| ] | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Created by Damiaan on 17/01/2019. | |
| // Copyright © 2019 Devian. All rights reserved. | |
| import AppKit | |
| class TableDataSource<C: RandomAccessCollection>: NSObject, NSTableViewDataSource { | |
| public struct ColumnSpecifier { | |
| let keyPath: PartialKeyPath<C.Element> | |
| fileprivate let transformer: Any? | |
| func getValue(from element: C.Element) -> Any { | |
| if let transformer = transformer { | |
| return (keyPath as! FullKeyPath).value(for: element, transformedBy: transformer) | |
| } else { | |
| return element[keyPath: keyPath] | |
| } | |
| } | |
| public init<T>(_ key: KeyPath<C.Element, T>, transform: ((T)->Any)? = nil) { | |
| keyPath = key | |
| transformer = transform | |
| } | |
| } | |
| var data: [C.Element] | |
| let columnSpecifiers: [NSUserInterfaceItemIdentifier: ColumnSpecifier] | |
| let columnIdentifiers: [PartialKeyPath<C.Element>: [NSUserInterfaceItemIdentifier]] | |
| init(data initialData: [C.Element], columns: [NSUserInterfaceItemIdentifier: ColumnSpecifier]) { | |
| data = initialData | |
| columnSpecifiers = columns | |
| columnIdentifiers = Dictionary(columns.map{($0.value.keyPath, [$0.key])}, uniquingKeysWith: +) | |
| } | |
| convenience init<Identifier: NSUserInterfaceItemIdentifierConvertible>(data initialData: [C.Element], columns: [Identifier: ColumnSpecifier]) { | |
| self.init( | |
| data: initialData, | |
| columns: Dictionary(uniqueKeysWithValues: columns.map{ ($0.key.id, $0.value) }) | |
| ) | |
| } | |
| func numberOfRows(in tableView: NSTableView) -> Int { | |
| return data.count | |
| } | |
| func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { | |
| if let column = tableColumn { | |
| return value(for: column.identifier, of: data[row]) | |
| } | |
| return nil | |
| } | |
| func value(for uiIdentifier: NSUserInterfaceItemIdentifier, of row: C.Element) -> Any { | |
| guard let specifier = columnSpecifiers[uiIdentifier] else { | |
| fatalError("There is no ColumnSpecifier set up for column \(uiIdentifier).") | |
| } | |
| return specifier.getValue(from: row) | |
| } | |
| } | |
| protocol NSUserInterfaceItemIdentifierConvertible: RawRepresentable where RawValue == String {} | |
| extension NSUserInterfaceItemIdentifierConvertible { | |
| var id: NSUserInterfaceItemIdentifier { return .init(rawValue) } | |
| } | |
| fileprivate protocol FullKeyPath { | |
| func value(for object: Any, transformedBy transform: Any) -> Any | |
| } | |
| extension KeyPath: FullKeyPath { | |
| func value(for object: Any, transformedBy transform: Any) -> Any { | |
| let element = (object as! Root)[keyPath: self] | |
| let function = transform as! ((Value)->Any) | |
| return function(element) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment