0

I have a main view controller ViewController and a secondary one: AddBookSheetViewController. The second view controller is presented as a sheet and is supposed to provide the function of scraping a website due to an user input identifier and subsequently yield the processed data back to the ViewController.

I found this related answer, which describes my problem in reverse and thus looks promising. I should be able to go on from there, right? Passing data from a ViewController to a TabViewController

Alas, the data doesn't get passed on. Here's my code:

@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
    }
}

Other's suggested different methods, e.g. here, but they seem to be either iOS specific or I was unable to implement them.

Can you identify the problem? (Perhaps in the AddBookSheetViewControllers viewDidLoad() function and perhaps specifically pertaining to the identifier ´parent`?) Thanks!

-- Edit

Answer

@vadian gave the crucial insight and certainly a more elegant solution altogether. Best to use his answer. In the current setup this works:

    override func viewDidLoad() {
        super.viewDidLoad()

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

this also works:

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

        }
    }

However, this causes some glitches in the main vc ViewController's NSTableView (where the data is deployed to).

Addition

/ ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** /
Nota Bene: According to @vadian, the following is particularly bad practice, i.e. wrong and is so much so that he suggested, I deleted it altogether. I'll leave it for educational purposes.
/ ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** /

Just prior to @vadian's answer I had some semi success trying it like this after reading this: macOS Swift master-detail delegate/protocol not working

That is, I was able to pass over to the main vc ViewController, but the app crashed with unexpected nil. (I didn't figure out why). Replacing AddBookSheetViewControllerDelegate with ViewController yielded the same behavior..

    override func viewDidLoad() {
        super.viewDidLoad()

        let mainViewController = ViewController()

        if let viewController = mainViewController as? AddBookSheetViewControllerDelegate {
            self.delegate = viewController
        }
    }
P. A. Monsaille
  • 152
  • 1
  • 1
  • 10
  • **Never** create a controller with the default initializer (`ViewController()`) if you are using storyboard or MainNib. It returns a new different instance. Remove the addition. It's wrong – vadian May 14 '19 at 17:01
  • It's not bad practice **it's wrong** – vadian May 14 '19 at 17:23

1 Answers1

0

Most likely the issue occurs because didSet is called sooner than viewDidLoad

But you don't need protocol / delegate at all in this case.

As the AddBook controller is presented modally use the property presentingViewController.
The sender parameter in the delegate method is unused.

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

I'd even create the Book in the add controller and return

parent.addBook(_ book: Book)
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Thanks! The `didSet` seems to work fine. I've edited the original post to (somehow) implement your answer. I'll give your method a try since the current solution causes some graphical glitches in the main window. And yeah, concerning the creation of the book in the `AddBook..` Controller was also my first thought. I think I ran into some issues due to completion closures and continued to go down a different path. – P. A. Monsaille May 14 '19 at 16:56