Swift - Ошибка (найдена ноль), вызывающая reloadData () из другого класса, но преуспевшая из собственного класса - PullRequest
0 голосов
/ 14 октября 2018

Я, очевидно, создаю перетаскиваемый ящик, который может либо выбирать файлы, щелкая по нему, либо перетаскивая файлы на нем , и я хочу, чтобы выбранные файлы были видны в таблице рядом сЭто.Моя логика заключается в том, что всякий раз, когда пользователь выбирает файлы из NSOpenPanel, он передает выбранные пути к файлам в CoreData, а затем массив извлекает их один за другим из CoreData и, наконец, обновляет NSTableViewсодержимое с использованием reloadData().

В принципе, моя проблема в том, что всякий раз, когда я пытаюсь вызвать ViewController().getDroppedFiles() из DropboxButton класса, я всегда получаю Fatal error: unexpectedly found nil while unwrapping an optional value.

My 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() длятабличное представление в моем классе ViewController из другого класса (DropboxButton: NSButton), чтобы всякий раз, когда пользователь перетаскивал файлы в раскрывающийся список, табличное представление перезагружалось?

PS Для меня это очень много значит,Мне действительно нужно исправить это в короткие сроки, есть ли кто-нибудь может потратить некоторое времямне помочь?

Ответы [ 2 ]

0 голосов
/ 17 февраля 2019

Я нашел это решение полезным для моего случая.

Я использовал обозреватель для передачи данных и вызова функций из других классов контроллеров, теперь я понимаю, что создавал новый экземпляр 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: для передачи данных между файлами и классами.

0 голосов
/ 17 октября 2018

Вам нужно вызвать getDroppedFiles() для загруженного экземпляра ViewController.

С помощью ViewController().getDroppedFiles() вы создаете новый экземпляр ViewController, который нигде не отображается (поэтому элементы управления не инициализируются, что приводит к ошибке nil).

...