Во-первых, я должен отметить, что это мое первое GUI-приложение (XIB) в Swift, другими словами, я работаю и пытаюсь изучить разработку программного обеспечения для Swift и MacOS. Я просмотрел несколько вопросов, здесь, в стеке, а также документацию Apple по NSTableView, но я застрял.
Попытка сделать простое приложение для чтения некоторых атрибутов выбранных файлов. У меня есть пользовательский NSView
, где пользователь перетаскивает файл и считывает с него некоторые атрибуты - и это нормально.
>>> print("\(fileDataToShow)\n\(resultTable)")
Optional([["filename": "foo.jpeg", "state": "1"],["filename": "bar.jpeg", "state": "1"]])
Optional(<NSTableView: 0x101203070>)
@IBOutlet weak var resultTable: NSTableView!
в верхней части файла, содержащего класс / NSView, показывает, что он подключен, MainMenu.XIB—ResultTable
.
Я придумал следующий код, пытаясь отобразить данные в NSTableView, из моего пользовательского class View: NSView {
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
<...>
func numberOfRowsInTableView(in tableView: NSTableView) -> Int {
return fileDataToShow?.count ?? 0
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{
var result:NSTableCellView
result = tableView.makeView(withIdentifier: (tableColumn?.identifier)!, owner: self) as! NSTableCellView
result.textField?.stringValue = fileDataToShow?[row][(tableColumn?.identifier.rawValue)!]! as! String
return result
}
resultTable?.beginUpdates()
// print(type(of:fileDataToShow)) // Optional<Array<Dictionary<String, Any>>>
resultTable.insertRows(at: IndexSet(integer: fileDataToShow?.count ?? 0), withAnimation: .effectFade)
resultTable.reloadData()
resultTable?.endUpdates()
}
Содержимое fileDataToShow
в порядке, но другие строки кода, .beginUpdates()
/ .insertRows(..
и т. Д., Похоже, не имеют никакого действия.
Как уже упоминалось, я не могу понять это и не знаю, где и как это выяснить ... Кто-нибудь получил несколько советов и / или указателей для меня?
Я определил все ключи в fileDataToShow
, чтобы они соответствовали Identifiers
в моем XIB.
Надеюсь, мне удалось объяснить мою проблему в порядке.
EDIT:
Область Debug выдает следующий вывод при запуске моего приложения:
*** Illegal NSTableView data source (<NSObject: 0x600000000b90>). Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
EDIT2 / Update:
Спасибо @vadian, но мне все еще не удалось это исправить, вот небольшое обновление.
Вот весь мой файл, DropZone.swift
:
`` `
class DropView: NSView/*, NSTableViewDataSource, NSTableViewDelegate*/ {
@IBOutlet weak var resultTable: NSTableView!
let dropZoneEnteredBackgroundColor = CGColor(red: 165/255, green: 165/255, blue: 165/255, alpha: 1.0)
let dropZoneExitedBackgroundColor = CGColor(red: 200/255, green: 200/255, blue: 200/255, alpha: 1.0)//NSColor.gray.cgColor
required init?(coder: NSCoder) {
super.init(coder: coder)
self.wantsLayer = true
self.layer?.backgroundColor = dropZoneExitedBackgroundColor
registerForDraggedTypes([NSPasteboard.PasteboardType.URL,
NSPasteboard.PasteboardType.fileURL])
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
self.layer?.backgroundColor = dropZoneEnteredBackgroundColor
return .copy
}
override func draggingEnded(_ sender: NSDraggingInfo) {
self.layer?.backgroundColor = dropZoneExitedBackgroundColor
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
guard let pasteboard = sender.draggingPasteboard.propertyList(forType:
NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as?
NSArray else {return false}
var droppedItems: [String: String] = [:]
for path in pasteboard {
guard let fullPath = path as? String else { return false }
let fileManager = FileManager.default
var isDir: ObjCBool = false
if fileManager.fileExists(atPath: fullPath, isDirectory:&isDir) {
if isDir.boolValue {
// the dropped item exists and it's a directory
droppedItems[path as! String] = "folder"
}
else {
// file exists and it's not a directory, hence a normal file
droppedItems[path as! String] = "file"
}
}
}
do {
var fileDataToShow = [[String:Any]]()
for object in droppedItems {
if object.value == "file" {
do {
//let fullPath = object.key
let attributes = try object.key.extendedAttributes() // Array<String>
let filename = object.key.fileName() + "." + object.key.fileExtension()
fileDataToShow.append(["state": "1",
"filename": filename,
"metadata":removed_attributes
])
}
catch {
debugPrint("Error info: \(error)")
}
}
else if object.value == "folder" {
// TODO
}
}
func numberOfRows(in tableView: NSTableView) -> Int {
return fileDataToShow.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{
let cell = tableView.makeView(withIdentifier: tableColumn?.identifier ?? NSUserInterfaceItemIdentifier(rawValue: ""), owner: self) as! NSTableCellView
// This line could crash if there values which are not String
cell.textField?.stringValue = fileDataToShow[row][tableColumn?.identifier.rawValue ?? ""] as! String
return cell
}
let insertionIndex = fileDataToShow.count
//debugPrint(resultTable) // Optional(<NSTableView: 0x10100ba10>)
//debugPrint(fileDataToShow) // [["filename": "img1.jpeg", "metadata": ["com.apple.metadata..", "com.a..."], "state": "1"]]
resultTable.insertRows(at: IndexSet(integer: insertionIndex), withAnimation: .effectGap)
} // do
return true
}
}
Теперь выдается следующая ошибка:
*** Canceling drag because exception 'NSTableViewException' (reason 'NSTableView error inserting/removing/moving row 2 (numberOfRows: 0).') was raised during a dragging session
Извините, но с момента последнего ответа от @vadian возникли проблемы с этим, так что нужно спросить еще раз.
Что я делаю не так?
РЕДАКТИРОВАТЬ 3:
Ценю ваши ответы, @vadian, но я не понимаю этого. У меня есть функции numberOfRows
и tableView
прямо под функцией init . И реализовал следующий код последнего в do-блоке, пытаясь обновить таблицу:
resultTable.beginUpdates()
var i = 0
for row in fileDataToShow {
print("state:",row["state"]!) // 1
print("filename:",row["filename"]!) // file.jpg
print("metadata:",row["metadata"]!) // ["com.apple.metadata..", "com.a..."]
resultTable.insertRows(at: IndexSet(integer: i), withAnimation: .effectFade)
i += 1
}
resultTable.endUpdates()
Новые строки добавляются в таблицу, но все они пусты. Как мне - никак - связать fileDataToShow
с resultTable.insertRows
.
Если вы понимаете мою плохую орфографию и суетливые вопросы :)
Свифт тяжело, но учиться весело!