Swift - 从另一个 class 调用 reloadData() 失败(发现 nil),但从自身 class 调用成功

Swift - Failed (found nil) calling reloadData() from another class but succeeded from self class

我显然正在设计一个拖放式投递箱,它可以通过单击或拖放文件来 select 文件,我想要selected 文件在它旁边的 table 中可见。我的设计逻辑是,每当用户 selects 来自 NSOpenPanel 的文件时,它会将 selected 文件路径传递到 CoreData,然后数组将它们一一检索来自 CoreData,最后,使用 reloadData().

更新 NSTableView 的内容

基本上,我的问题是每当我尝试从 DropboxButton class 调用 ViewController().getDroppedFiles() 时,我总是得到 Fatal error: unexpectedly found nil while unwrapping an optional value.

我的ViewController.swift:

import Cocoa

class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        getDroppedFiles()
    }

    @IBOutlet weak var DroppedFilesTableView: NSTableView!

    var droppedFiles: [DroppedFiles] = [] // Core Data class definition: DroppedFiles

    func numberOfRows(in tableView: NSTableView) -> Int {
        return droppedFiles.count
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        let droppedFilesCollection = droppedFiles[row]

        if (tableView?.identifier)!.rawValue == "fileNameColumn" {
            if let fileNameCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "fileNameCell")) as? NSTableCellView {
                fileNameCell.textField?.stringValue = droppedFilesCollection.fileName!
                return fileNameCell
            }
        }  else if (tableView?.identifier)!.rawValue == "filePathColumn" {
             if let filePathCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "filePathCell")) as? NSTableCellView {
                 filePathCell.textField?.stringValue = droppedFilesCollection.filePath!
                 return filePathCell
             }
        }
        return nil
    }

    @IBAction func DropboxClicked(_ sender: NSButton) {
        // selected file paths
        for filePath in selectedFilePaths {
            if let context = (NSApp.delegate as? AppDelegate)?.persistentContainer.viewContext {
                let droppedFilesData = DroppedFiles(context: context)
                droppedFilesData.fileName = getFileName(withPath: filePath)
                droppedFilesData.filePath = filePath
                do {
                    try context.save()
                } catch {
                    print("Unable to save core data.")
                }
            }
            getDroppedFiles()
        }
    }

    func getDroppedFiles() {
        if let context = (NSApp.delegate as? AppDelegate)?.persistentContainer.viewContext {
            do {
                try droppedFiles = context.fetch(DroppedFiles.fetchRequest())
            } catch {
                print("Unable to fetch core data.")
            }
        }
        DroppedFilesTableView.reloadData() // Fatal Error: unexpectedly found nil while unwrapping an optional value (whenever I call this function in other class)
    }


}

我正在使用一个按钮 (NSButton) 作为保管箱(它有自己的 class),可以轻松单击它并且还支持拖动选项。

我的DropboxButton.swift:

import Cocoa

class DropboxButton: NSButton {

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        registerForDraggedTypes([NSPasteboard.PasteboardType.URL, NSPasteboard.PasteboardType.fileURL])
    }

    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        // some other codes
        return .copy
    }

    override func draggingExited(_ sender: NSDraggingInfo?) {
        // some other codes
    }

    override func draggingEnded(_ sender: NSDraggingInfo) {
        // some other codes
    }

    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
        guard let pasteboard = sender.draggingPasteboard.propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? NSArray,
            let filePaths = pasteboard as? [String] else {
                return false
        }

        for filePath in filePaths {
            if let context = (NSApp.delegate as? AppDelegate)?.persistentContainer.viewContext {
                let droppedFilesData = DroppedFiles(context: context)
                droppedFilesData.fileName = getFileName(withPath: filePath)
                droppedFilesData.filePath = filePath
                do {
                    try context.save()
                } catch {
                    print("Unable to save core data.")
                }
            }
            ViewController().getDroppedFiles() // found nil with reloadData() in ViewController.swift
        }
        return true
    }
}

这是我的界面和代码逻辑:

那么,我怎样才能 reloadData() 在我的 ViewController class 中从另一个 class (DropboxButton: NSButton) 中查看 table,所以每当用户将文件拖放到保管箱中时,table 视图将重新加载?

P.S。完成这件事对我来说意义重大,我真的需要在短时间内解决这个问题,有没有人可以花一些时间帮助我?

您需要在 ViewController 的加载实例上调用 getDroppedFiles()

使用 ViewController().getDroppedFiles() 您正在创建一个 ViewController 的新实例,该实例不会在任何地方显示(因此控件未初始化导致 nil 错误)。

我发现这个解决方案对我的情况很有用。

我使用观察器从其他控制器 类 传递数据和调用函数,现在我明白我正在创建一个未加载的 ViewController 的新实例。这是我的代码:

ViewController.swift:

class ViewController: NSViewController {
    // other codes
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(getDroppedFiles), name: NSNotification.Name(rawValue: "reloadTableViewData"), object: nil)
    }
    @objc func getDroppedFiles() {
        DroppedFilesTableView.reloadData()
    }
}

DropboxButton.swift:

class DropboxButton: NSButton {
    // other codes
    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
        // other codes
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTableViewData"), object: nil)
        return true
    }
}

现在,一切正常,我什至可以添加一个 userInfo: 来在文件和 类 之间传递数据。