2017-07-07 40 views
3

我正在使用包含两个视图控制器:“TableViewController”和“EntryViewController”的NSSplitView与Swift OSX应用程序。我使用委托来传递一个自定义的NSObject(“Entry”),点击从TableViewController到SplitViewController,然后返回到EntryViewController。Swift OSX - 委托协议函数返回nil,解包文本域值时崩溃

我的问题是这样的:当在EntryViewController,收到任何企图其属性分配给文本字段值结果意外地发现零类型错误的的Entry对象,别提了IBOutlets是正确的链接,并且它既可以打印Entry.property 文本字段值(只要它在不同的,不相关的函数中)。

我已经尝试了许多安排来解决这个问题,这就是为什么当前的配置可能有点过于复杂。直接从表VC到Entry VC的委托关系导致了相同的问题。

即使在委托调用之前加载了视图,IBOutlets是否还没有连接?我已经阅读了很多许多关于委托的文章(主要是针对iOS),但似乎无法找到我的问题的根源。我会第一个承认我对斯威夫特的把握有点零碎,所以我很乐意看到我试图做的只是简单的/黑客的编码,我应该尝试一些完全不同的东西。

感谢您的帮助!

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 
    } 

} 
+0

请注明答复是否能解决你的问题。 – Efren

回答

1

你并不需要一个代表/协议,因为那里是EntryViewController参考(contentView) - 顺便说一下实例创建用EntryViewController()编辑的是而不是的实例化的实例在viewDidLoad

只需使用contentView参考:

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

啊!我认为这会更简单一些。然而,现在,“contentView?.sendSecondSelection(entrySelection)”提供了一个错误 - contentView是NSViewController类型的值,并且没有成员“sendSecondSelection”。我错过了明显的东西吗? –

+0

如果类型不更改,请声明'var contentView:EntryViewController?'。你还应该声明'entrySelection'比'NSObject'更具体。 Swift不是像Objective-C – vadian

+0

这样的*类型 - 不是真的*语言。是的!这有帮助,并且让我意识到splitviewselection委托被设置为SplitViewController的单独实例。没有什么是指我认为是的例子。 –