Following a solution here, I was able to reorder the rows of a NSTableView
, but the application doesn't save/load the table view with the new row order after quitting.
The view controller:
import Cocoa
@objcMembers class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
@IBOutlet weak var tableView: NSTableView!
var persons = [Person]()
override func viewDidLoad() {
super.viewDidLoad()
persons = Person.loadFromFile()!
tableView.delegate = self
tableView.dataSource = self
tableView.registerForDraggedTypes([.string])
}
override func viewDidDisappear() {
Person.saveToFile(persons: persons)
}
func numberOfRows(in tableView: NSTableView) -> Int {
return persons.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return persons[row]
}
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
let data = NSKeyedArchiver.archivedData(withRootObject: rowIndexes)
pboard.declareTypes([.string], owner: self)
pboard.setData(data, forType: .string)
return true
}
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
if dropOperation == .above {
return .move
} else {
return []
}
}
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
let pasteboard = info.draggingPasteboard()
let pasteboardData = pasteboard.data(forType: .string)
if let pasteboardData = pasteboardData {
if let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: pasteboardData) as? IndexSet {
var oldIndexOffset = 0
var newIndexOffset = 0
for oldIndex in rowIndexes {
if oldIndex < row {
// Dont' forget to update model
tableView.moveRow(at: oldIndex + oldIndexOffset, to: row - 1)
oldIndexOffset -= 1
} else {
// Dont' forget to update model
tableView.moveRow(at: oldIndex, to: row + newIndexOffset)
newIndexOffset += 1
}
}
}
}
return true
}
The model:
import Cocoa
@objcMembers class Person: NSObject, Codable {
[...]
static let DocumentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("persons").appendingPathExtension("plist")
[...]
static func loadFromFile() -> [Person]? {
guard let codedPersons = try? Data(contentsOf: ArchiveURL) else {return nil}
let decoder = PropertyListDecoder()
return try? decoder.decode(Array<Person>.self, from: codedPersons)
}
static func saveToFile(Persons: [Person]) {
let encoder = PropertyListEncoder()
let codedPersons = try? encoder.encode(persons)
try? codedPersons?.write(to: ArchiveURL)
}
}
Do I have to modify persons
where the // Dont' forget to update model
comments are?
EDIT: I was able to save/load the reordering of the table by removing then inserting an element in persons
in each of the // Dont' forget to update model
scopes.
Thank you.