Swift OSX - 委托协议函数返回nil,在解包文本字段值时崩溃

时间:2017-07-07 16:10:15

标签: swift xcode macos delegates

我正在使用Swift开发一个OSX应用程序,该应用程序使用一个NSSplitView,它包含两个视图控制器:“TableViewController”和“EntryViewController”。我正在使用委托,以便在从TableViewController到SplitViewController的点击时传输自定义NSObject(“Entry”),然后返回到EntryViewController。

我的问题是这个:当在EntryViewController中收到Entry对象时,任何将其属性分配给文本字段值的尝试都会导致意外找到nil 类型错误,不要介意IBOutlets正确链接,并且它可以打印Entry.property 文本字符串值(假设它在不同的,无关的函数中)。

我已经尝试了很多安排来解决这个问题,这就是当前配置可能有点过于复杂的原因。直接从表VC到Entry VC的委托关系引起了同样的问题。

有没有某种方式IBOutlets没有连接,即使在调用委托之前加载了视图?我已经阅读了许多关于委托的许多文章 - 主要是针对iOS的 - 但似乎无法找到问题的根源。我是第一个承认我对Swift的掌握有点零碎的人,所以我很乐意接受这样的可能性,即我想要做的只是坏/ hacky编码,我应该尝试一些完全不同的东西。

感谢您的帮助!

TableViewController:

protocol SplitViewSelectionDelegate: class {
    func sendSelection(_ entrySelection: NSObject)
}

class TableViewController: NSViewController {

    @IBOutlet weak var searchField: NSSearchField!
    @IBOutlet var tableArrayController: NSArrayController!
    @IBOutlet weak var tableView: NSTableView!

    var sendDelegate: SplitViewSelectionDelegate?

    dynamic var dataArray = [Entry]()

// load array from .plist array of dictionaries

    func getItems(){
        let home = FileManager.default.homeDirectoryForCurrentUser
        let path = "Documents/resources.plist"
        let urlUse = home.appendingPathComponent(path)

        let referenceArray = NSArray(contentsOf: urlUse)
        dataArray = [Entry]()

        for item in referenceArray! {
            let headwordValue = (item as AnyObject).value(forKey: "headword") as! String
            let defValue = (item as AnyObject).value(forKey: "definition") as! String
            let notesValue = (item as AnyObject).value(forKey: "notes") as! String

            dataArray.append(Entry(headword: headwordValue, definition: defValue, notes: notesValue))
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.sendDelegate = SplitViewController()
        getItems()
        print("TVC loaded")
        // Do any additional setup after loading the view.
    }   

// send selection forward to entryviewcontroller

    @IBAction func tableViewSelection(_ sender: Any) {

        let index = tableArrayController.selectionIndex
        let array = tableArrayController.arrangedObjects as! Array<Any>
        let obj: Entry
        let arraySize = array.count
        if index <= arraySize {
            obj = array[index] as! Entry
            print(index)
            print(obj)
            sendDelegate?.sendSelection(obj)
        }
        else {
            print("index unassigned")
        }
        }

}

SplitViewController:

protocol EntryViewSelectionDelegate: class {
    func sendSecondSelection(_ entrySelection: NSObject)
}

class SplitViewController: NSSplitViewController, SplitViewSelectionDelegate {

    var delegate: EntryViewSelectionDelegate?
    @IBOutlet weak var mySplitView: NSSplitView!

    var leftPane: NSViewController?
    var contentView: NSViewController?

    var entrySelectionObject: NSObject!

    override func viewDidLoad() {

        super.viewDidLoad()

    // assign tableview and entryview as child view controllers
        let story = self.storyboard

        leftPane = story?.instantiateController(withIdentifier: "TableViewController") as! TableViewController?
        contentView = story?.instantiateController(withIdentifier: "EntryViewController") as! EntryViewController?

        self.addChildViewController(leftPane!)
        self.addChildViewController(contentView!)

        print("SVC loaded")
}

    func sendSelection(_ entrySelection: NSObject) {
        self.delegate = EntryViewController() //if this goes in viewDidLoad, then delegate is never called/assigned
        entrySelectionObject = entrySelection
        print("SVC:", entrySelectionObject!)
        let obj = entrySelectionObject!
        delegate?.sendSecondSelection(obj)
    }

}

最后,EntryViewController:

class EntryViewController: NSViewController, EntryViewSelectionDelegate {

    @IBOutlet weak var definitionField: NSTextField!
    @IBOutlet weak var notesField: NSTextField!
    @IBOutlet weak var entryField: NSTextField!

    var entryObject: Entry!

    override func viewDidLoad() {
        super.viewDidLoad()
        print("EVC loaded")
    }

    func sendSecondSelection(_ entrySelection: NSObject) {
        self.entryObject = entrySelection as! Entry
        print("EVC:", entryObject)
        print(entryObject.headword)
// The Error gets thrown here:
        entryField.stringValue = entryObject.headword
    }

}

1 个答案:

答案 0 :(得分:1)

您不需要委托/协议,因为有EntryViewControllercontentView)的引用 - 用EntryViewController()创建的实例 viewDidLoad中的实例化实例。

只需使用contentView参考:

func sendSelection(_ entrySelection: NSObject) {
    contentView?.sendSecondSelection(entrySelection)
}