Swift-从另一个类调用reloadData()失败(发现为零),但从自类成功

时间:2018-10-14 10:14:07

标签: macos cocoa nstableview xcode10 swift4.2

我显然正在设计一个拖放保管箱,它可以通过单击选择文件或将其拖放到文件上,我希望所选文件在下一个表格中可见对它。我的设计逻辑是,每当用户从NSOpenPanel中选择文件时,它将选择的文件路径传递到CoreData中,然后数组从CoreData中一个接一个地检索它们,最后,请使用NSTableView更新reloadData()的内容。

基本上,我的问题是,每当我尝试从ViewController().getDroppedFiles()类调用DropboxButton时,总是得到一个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)作为保管箱(它具有自己的类),可以轻松单击该按钮并支持拖动选项。

我的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
    }
}

这是我的界面和代码逻辑: user interface and code logic

因此,我如何reloadData()从另一个类(DropboxButton: NSButton)中获取ViewController类中的表视图,以便每当用户将文件拖放到保管箱中时,表视图就会重新加载?

P.S。要做到这一点对我来说意义重大,我真的需要在短时间内解决此问题,有人可以花一些时间来帮助我吗?

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

我发现此解决方案对我的情况有用。

我使用观察者传递来自其他控制器类的数据和调用函数,现在我知道我正在创建一个未加载的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:在文件和类之间传递数据。