在 swift for macOS 中使用委托将数据传递到主视图控制器

Passing data to main view controller with delegate in swift for macOS

我有一个主视图控制器 ViewController 和一个辅助视图控制器:AddBookSheetViewController。第二个视图控制器显示为 sheet 并且应该提供由于用户输入标识符而抓取网站的功能,随后将处理后的数据返回给 ViewController.

我找到了这个相关的答案,它反向描述了我的问题,因此看起来很有希望。我应该可以从那里继续,对吧? Passing data from a ViewController to a TabViewController

唉,数据没有得到传递。这是我的代码:

@objc protocol AddBookSheetViewControllerDelegate {
    func addBookFromExtern(sender: AddBookSheetViewController, data: [String])
}

class AddBookSheetViewController: NSViewController {

    weak var delegate: AddBookSheetViewControllerDelegate?

    @IBOutlet weak var isbnSheetTextField: NSTextField!


    var bibTex = "" {
        didSet {
            //: sets as expected
            print(oldValue, "replaced for new:", bibTex)
            let bookFromBibtex = BookFromBibtex()
            let texData = bookFromBibtex.getInfo(bibtex: bibTex)

            //: prints
            print("now we've reached delegate")
            //: nothing happens on the other side
            self.delegate?.addBookFromExtern(sender: self, data: texData)
            //: prints
            print("now we've passed delegate")

        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        //
        //: might this be problem? "parent"?
        //
        if let viewController = parent as? ViewController {
            self.delegate = viewController
        }
    }

    @IBAction func getBookSheetButton(_ sender: Any) {

        if isbnSheetTextField.stringValue != "" {
            //: .letterCount is a String extension
            if isbnSheetTextField.stringValue.letterCount <= 0 {

                //: scrape() does the URLSession and regex work
                scrape(isbn: isbnSheetTextField.stringValue)
                //: cont'd in bibTex didSet

            } else { print("Unvalid ISBN.")}

        } else {print ("Enter ISBN.") }

    }

}
class ViewController: NSViewController, NSWindowDelegate, AddBookSheetViewControllerDelegate {


    func addBookFromExtern(sender: AddBookSheetViewController, data: [String]) {
        let newBook =  Book(author: data[0], title: data[1], lentBy: "", signature: "", comment: "", isbn: "123", lentDate: "", creationDate: Date())
        self.BookArrayController.addObject(newBook)

        print("signal received")  //: doesn't get triggered
    }
}

其他人建议的不同方法,例如here,但它们似乎是 iOS 特定的,或者我无法实现它们。

你能找出问题所在吗? (也许在 AddBookSheetViewControllers viewDidLoad() 函数中,也许特别与标识符“parent”有关?)谢谢!

-- 编辑

回答

@vadian 给出了关键的见解,当然也提供了一个更优雅的解决方案。最好使用他的答案。在当前设置中,这有效:

    override func viewDidLoad() {
        super.viewDidLoad()

        //: or presentingViewController
        if let viewController = presenting as? ViewController {
            self.delegate = viewController
        }
    }

这也有效:

    override func viewDidLoad() {
        super.viewDidLoad()
          let mainViewController = presenting as! ViewController
          self.delegate = mainViewController

        }
    }

但是,这会导致主要 vc ViewController 的 NSTableView(数据部署到的位置)出现一些故障。

加法

/ ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** /
诺塔贝内: 根据@vadian 的说法,以下是特别糟糕的做法,即错误的,以至于他建议我将其完全删除。我会把它留作教育目的。
/ ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * * ** ** ** ** ** /

就在@vadian 的回答之前,我在阅读这篇文章后尝试了一些成功:macOS Swift master-detail delegate/protocol not working

也就是说,我能够传递到主要 vc ViewController,但应用程序因意外的 nil 而崩溃。 (我没弄明白为什么)。将 AddBookSheetViewControllerDelegate 替换为 ViewController 会产生相同的行为..

    override func viewDidLoad() {
        super.viewDidLoad()

        let mainViewController = ViewController()

        if let viewController = mainViewController as? AddBookSheetViewControllerDelegate {
            self.delegate = viewController
        }
    }

问题的发生很可能是因为 didSetviewDidLoad

调用得早

但是在这种情况下你根本不需要协议/委托。

由于 AddBook 控制器以模态方式呈现,因此使用 属性 presentingViewController.
委托方法中的sender参数未使用。

let parent = presentingViewController as! ViewController
parent.addBook(_ data: [String])

我什至会在添加控制器中创建图书 return

parent.addBook(_ book: Book)