My view controller opens a directory, counts the file types therein and stores the results in a dictionary [String:Int] of filetypes and count. I have a TableView that displays this.
The first time I open a directory the ViewController correctly displays the information in the FileTypeTableview. If I try to open another directory, execution gets to the line:
let dialogButton = dialog.runModal()
Then immediately jumps to a line in my TableView function and throws an index out of range here:
val = types[row]
Types is a [String] and shows 0 elements and row is an Int and shows 0. I'm confused by the fact this happens at the dialog.runModal() function call.
Below are the functions that get the directory and display the TableViews. I'm very new to Swift and MacOS programing and I'd appreciate any insights.
@IBAction func getFolder(_ sender: Any) {
let dialog = NSOpenPanel()
dialog.canChooseDirectories = true
dialog.canChooseFiles = false
allFiles = []
fileTypesDict.removeAll()
let dialogButton = dialog.runModal()
if let theURL = dialog.url {
theDirectory = theURL.path
allFilesAsPaths = getAllFiles2(atDirectoryPath: theURL.path)
allFilesAsPaths.sort()
}
fileCountLabel.stringValue = String(allFilesAsPaths.count)
mainTableView2.reloadData()
fileTypeTableView.reloadData()
}
func numberOfRows(in tableView: NSTableView) -> Int {
var numberOfRows : Int = 0
if tableView == mainTableView2 {
print("number of rows for mainTableView2")
numberOfRows = allFilesAsPaths.count
} else if tableView == fileTypeTableView {
print("number of rows for fileTypeTableView")
numberOfRows = fileTypesDict.count
} else if tableView == exifTableView {
numberOfRows = exifData.count
print("exifData.count = \(exifData.count)")
print("number of rows for exifTableview \(numberOfRows)")
}
return numberOfRows
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
var val : String = ""
if tableView == mainTableView2 {
val = allFilesAsPaths[row]
}
if tableView == exifTableView {
if tableColumn?.identifier.rawValue == "tag" {
let tagArray : [String] = Array(exifData.keys)
val = tagArray[row]
} else if tableColumn?.identifier.rawValue == "value" {
let valueArray : [String] = Array(exifData.values)
val = valueArray[row]
}
}
if tableView == fileTypeTableView {
let types : [String] = Array(fileTypesDict.keys)
let counts : [Int] = Array(fileTypesDict.values)
if tableColumn?.identifier.rawValue == "type" {
val = types[row]
} else {
val = String(counts[row])
}
}
return val
}
I think you should try to remove
allFiles = []
fileTypesDict.removeAll()
And simply set all your arrays at once after dialog validation. Because it looks like presenting the dialog triggers an update of the table, but at this time, your objects are not sync because you do some work before, and after.
BTW, it would be clearer if you do separate table classes than dealing with if tableView == ... {}
. You take the risk that your code gradually become inextricable. I've been there already ;)