# Presenting and passing data to a modal view controller without using prepare(for:sender:) method

I am using a toolbar button to present a modal view controller (in which I let the user export data as a PDF file). The main section of my app is a UITableViewController subclass embedded in a UINavigationController.

Here is a schematic of my layout.

The modal itself is embedded in a UINavigationController as I need it to have a bottom toolbar. It also has a transparent background and is presented using .overCurrentContext, so the main screen of the user's data blurs underneath.

I found that to get it to float over everything else (including the navigation bar etc), I had to present it from the UINavigationController (otherwise the main navigation bar and toolbar appeared on top of it). The problem with this is that the UITableViewController method prepare(for:sender:) is not called.

I call the segue to the modal view controller like this (from the UITableViewController subclass):

// User taps EXPORT button
@objc func exportButtonTapped(_ sender: UIBarButtonItem) {
}


In order to transfer the array of user data to the modal view controller, I have called the following code in the modal view controller:

override func viewDidLoad() {
// Get data from array in main table view controller
let myTableVC = masterNav.topViewController as! MyTableViewController
self.userData = myTableVC.userData // This is of type: [MyObject]
}


The data is then rendered to a PDF (using HTML templating) in the modal view controller's viewWillAppear() method. This works as expected.

However, I have some concerns about doing it this way:

1. Is it guaranteed that viewDidLoad() will finish before viewWillAppear() is called? Will an even a larger data set be available for rendering as PDF in viewWillAppear()?
2. Is it acceptable to present modally from the UINavigationController?
3. Should I be subclassing the main UINavigationController and using its prepare(for:sender:) method (if this is even an option)?
4. In the performSegue(withIdentifier:sender:) method, does the sender argument make any difference?
5. Is it preferable to use present() rather than a segue?

I would of course be grateful for any other advice or refinements to the code. It seems to work as expected but I just want to make sure I following best practice as far as possible.

Is it guaranteed that viewDidLoad() will finish before viewWillAppear() is called? Will an even a larger data set be available for rendering as PDF in viewWillAppear()?

Yes. It needs to be loaded before it will appear.

Is it acceptable to present modally from the UINavigationController?

I think it is.

Should I be subclassing the main UINavigationController and using its prepare(for:sender:) method (if this is even an option)?

It sounds a bit complicated. prepare(for:sender:) is not a very clean way to do transfer data to begin with and only useful when you use segues in a regular way. Why don't you create the ModalViewController in code, set the value and then push it through code instead?

In the performSegue(withIdentifier:sender:) method, does the sender argument make any difference?

I used it in rare occasions to understand where the push was coming from.

Is it preferable to use present() rather than a segue?

I think in your case yes.

• Thanks for your answer. I like these ideas - I’m going to try making the view controller in code. Sep 1 '18 at 20:55
• That's not necessary. You can instantiate it from a storyboard or XIB if you want and then push it all through code. Sep 1 '18 at 21:47
• Ah yes I see what you mean. That sounds easier as I already have my Storyboard made! Sep 2 '18 at 6:03