How to Instantiate and Load a View Controller Before Segueing to It Using Swift

How to instantiate and load a view controller before segueing to it using swift

You can move all the heavy code out of viewDidLoad() into some custom method

func prepare() {
// Something hard
}

than you can prepare your controller at anytime and store it

var heavyController: HeavyViewController?

override func viewDidLoad() {
super.viewDidLoad()
heavyController = HeavyViewController()
heavyController?.prepare()
}

than just use heavyController in segue instead of creating new one. Hope this helps.

P.S. consider moving heavy parts of code into background thread, you can check the example.

UPDATE:
To show your prepared controller using segue do something like this:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "HeavyController" {
present(heavyController, animated: true, completion: nil)
}
}

Instantiate and Present a viewController in Swift

This answer was last revised for Swift 5.4 and iOS 14.5 SDK.


It's all a matter of new syntax and slightly revised APIs. The underlying functionality of UIKit hasn't changed. This is true for a vast majority of iOS SDK frameworks.

let storyboard = UIStoryboard(name: "myStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "myVCID")
self.present(vc, animated: true)

Make sure to set myVCID inside the storyboard, under "Storyboard ID."

Sample Image

Swift how to trigger prepare for segue before target view load?

What I would do first is to DELETE ❌ the segue you've probably created by drag and drop from the button on VC1 to VC2. Replace it by a regular segue which is not attached to any UI component so that you can trigger it manually in code (from its identifier, don't forget to provide one). It will allow you to first perform some asynchronous code, and only when getting the callback trigger the navigation (if data fetch is successful).

To create such a segue:

  1. click on your VC1 in the storyboard => A small rectangle with icons should be now displayed right above the VC1
  2. Ctrl + drag from the yellow icon (probably at the most left of that rectangle) to the VC2 (on main view, does not rally matter where you drop it as long as it is on VC2)
  3. Provide identifier after having clicked on the newly created segue so that you can trigger it from code

That was for the segue, but now, when to trigger it?

  1. Create an an @IBAction on the button which is suppose to trigger the fetch + navigation (or equivalent, like didSelectRowAtIndexPath)
  2. This IBAction should call another method like the following:
private func fetchPostingAndNavigateIfSuccessful() {
// Should probably first set the activity indicator to `.startAnimating()`
let docRef = db.collection("Posting").getDocuments() { [weak self] querySnapshot, error in
// Should probably set the activity indicator to `.stopAnimating()`
guard error != nil,
let documents = querySnapshot?.documents else {
print("error getting documents") //probably a good place to display an alert
return
}
let postingsData = documents.map { $0.data() }
self?.performSegue(withIdentifier: "NavigateToPostingsSegue", sender: postingsData)
}
}

Your prepare for segue would then look like that:


override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let postingListTableViewController = segue.destination as? PostingListTableViewController,
let postingsData = sender as? [[String:Any]] {
postingListTableViewController.updatedPostings = postingsData
}
}

Initialising a ViewController before Segue

Segues should be subclassed only when you need to show custom animation/transition during the segue.

In usual scenario, you would want to do this:

__ block Destination *destinationVC = [self.storyboard instantiateViewControllerWithIdentifier:@"destination "];

//START BUSY CURSOR HERE
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
// init whatever you want for destinationVC HERE.
dispatch_async(dispatch_get_main_queue(),
^{
//STOP BUSY CURSOR
//PERFORM UI UPDATE HERE
[self presentViewController:destinationVC animated:YES completion:nil];
});

Make instance of view controller and segue to it programatically

You want to use presentViewController instead of performSegue:

// however you want to initialize the new vc
let vc2 : View2 = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("view2.id") as! View2

an alternate way to init the vc is to do this:

let vc2 = View2()

and then set the data and present:

vc2.index = index // whatever you want to pass
self.presentViewController(vc2, animated: true, completion: nil)

Otherwise you could create a new view controller in your storyboard, but I wouldn't recommend it.

How to load initial view controller in Swift?

I solved the problem by changing resetAppToFirstController method to:

self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier(PageNames.LOGIN_PAGE) as LoginPageViewController

and firing the following code when Logout is clicked:

let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
appDelegate.resetAppToFirstController()

However, I have no idea why this is worked. Any little explanation would be great.

Pass data to view controller before initializer when using segues. (Swift)

There is two possible options as you mentioned:

The first one is the easiest which is to pass the data in prepareForSegue. which you don't have to care about dismissing the controller or keeping a track of inner view controllers,because storyboard will take care of it.

The second way is to set a Storyboard ID in storyboard,for the controller you need to present programmatically, which need more things to handle, like to dismiss the controller or keep track of inner presented controllers.

let nextViewControllerName = storyboard?.instantiateViewControllerWithIdentifier("Storyboard ID") as! nextViewControllerName
nextViewControllerName.event = self.event
self.presentViewController(nextViewControllerName, animated: true, completion: nil).

At the end they does the same purpose.

Note: You should always pass the data before presenting the controller.



Related Topics



Leave a reply



Submit