Skip to content

Instantly share code, notes, and snippets.

@robertmryan
Created May 23, 2024 05:50
Show Gist options
  • Save robertmryan/0255230890a86931d06a5ed439171dfb to your computer and use it in GitHub Desktop.
Save robertmryan/0255230890a86931d06a5ed439171dfb to your computer and use it in GitHub Desktop.
import Foundation
class ViewController: NSViewController {
private let scrollView = NSScrollView()
private let tableView = NSTableView()
private let arrayController = NSArrayController()
private var observers: [NSKeyValueObservation] = []
// Your data source array
@objc dynamic var people: [Person] = [
Person(name: "John", age: 25),
Person(name: "Jane", age: 30),
Person(name: "Alice", age: 28)
]
override func viewDidLoad() {
super.viewDidLoad()
configure()
}
}
private extension ViewController {
func configure() {
configureTableView()
configureScrollView()
addObservers()
}
func configureTableView() {
tableView.translatesAutoresizingMaskIntoConstraints = false
let nameColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("NameColumn"))
nameColumn.title = "Name"
tableView.addTableColumn(nameColumn)
let ageColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("AgeColumn"))
ageColumn.title = "Age"
tableView.addTableColumn(ageColumn)
// Create and configure the NSArrayController
arrayController.bind(.contentArray, to: self, withKeyPath: "people", options: nil)
// Bind the table view to the array controller
tableView.bind(.content, to: arrayController, withKeyPath: "arrangedObjects", options: nil)
tableView.bind(.selectionIndexes, to: arrayController, withKeyPath: "selectionIndexes", options: nil)
tableView.bind(.sortDescriptors, to: arrayController, withKeyPath: "sortDescriptors", options: nil)
// Bind columns to the array controller
nameColumn.bind(.value, to: arrayController, withKeyPath: "arrangedObjects.name", options: nil)
ageColumn.bind(.value, to: arrayController, withKeyPath: "arrangedObjects.age", options: nil)
}
func configureScrollView() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
// Set up constraints to ensure the table view fills the parent view
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
scrollView.documentView = tableView
scrollView.hasVerticalScroller = true
}
// for demonstration purposes, I'm just going to observe name changes
func addObservers() {
for person in people {
let observer = person.observe(\.name, options: [.old, .new]) { [weak self] _, change in
guard let self else { return }
print(people)
}
observers.append(observer)
}
}
}
class Person: NSObject {
@objc dynamic var name: String
@objc dynamic var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
extension Person {
override var description: String { "\(name) is \(age) years old" }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment