Make Segue programmatically in Swift - ios

I have two VCs: VC1 and VC2.
In VC1, I have a finish button which I programmatically made and a result array I want to pass to VC2.
I know how to make Segue in Storyboard, but I cannot do that at this moment since the finish button is programmatically made.
If I want to pass result array using segue, is there a way to make the segue programmatically? If this is not possible, should I just present VC2 using presentViewController and set a delegate to pass the result array?

You can do it like proposed in this answer:
InstantiateViewControllerWithIdentifier.
Furthermore I am providing you the code from the linked answer rewritten in Swift because the answer in the link was originally written in Objective-C.
let vc = UIStoryboard(name:"Main", bundle:nil).instantiateViewController(withIdentifier: "identifier") as! SecondViewController
vc.resultsArray = self.resultsArray
EDIT:
Since this answer draws some attention I thought I provide you with another more failsafe way. In the above answer the application will crash if the ViewController with "identifier" is not of type SecondViewController. In Swift you can prevent this crash by using optional binding:
guard let vc = UIStoryboard(name:"Main", bundle:nil).instantiateViewControllerWithIdentifier("identifier") as? SecondViewController else {
print("Could not instantiate view controller with identifier of type SecondViewController")
return
}
vc.resultsArray = self.resultsArray
self.navigationController?.pushViewController(vc, animated:true)
This way the ViewController is pushed if it is of type SecondViewController. If can not be casted to SecondViewController a message is printed and the application remains on the current ViewController.

You can still create the segue in Interface Builder by dragging from VC1 to VC2 - just drag from/to the little yellow circle at the top of the VC. Give this segue a unique name in IB, and in your finish function you can call performSegueWithIdentifier:, pass in the name of your segue, and that's it. In the prepareForSegue method you can find out which segue is being performed by accessing segue.identifier, and if it's the segue in question you can get a pointer to segue.destinationViewController and pass your data on that way.

Related

How do I send self as a delegate from one viewController in a tabViewController to another viewController

I have a custom tabViewController and I would like to pass self as a delegate from viewController one to viewController two (which is modal). The problem is that when I go between viewControllers using the tabs the prepare function isn't triggered as the tabViewController handle the transitions I suppose.
So how do I make this happen? How do I pass self from one viewController to the next.
Actually inside any VC that's inside the tab you could do
// suppose you need to access second tab
if let targetVC = self.tabBarController?.viewControllers[1] as? SecondVC {
// do what you want
}

Swift 4, load next ViewController

In my app I have two View Controllers embedded in Navigation Controller. And I want to have an option to get data from the SecondVC while only the FirstVC is opened. So it's like I don't want a user to see (or at least interact) with the SecondVC.
The point is
So user just taps on the button on the FirstVC (without opening SecondVC before) and I can get access to the data on the SecondVC.
How can I get data from the next view controller (SecondVC) in a navigation controller without opening it? Or at least not letting user to interact with it.
For now my only ideas are:
To push segue when user taps a button, get it into memory, load data and then dismiss it. But that doesn't look good when view controllers change so fast.
To present next view controller modally offscreen, get data and dismiss it. So the user won't even see that another view controller opened.
Edit:
I need to get access not just to method or smth. I need to get to the #IBOutlet. To the subclass of UIView (working with CorePlot) to be exactly
You should never call loadView() directly.
Instantiate your UIViewController and then call loadViewIfNeeded().
Calling this method loads the view controller’s view from its storyboard file, or creates the view as needed based on the established rules.
EDIT:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// make sure that the value is an optional so that you can unset it later. This one is optional because we use optional casting (with as?)
var vc = storyboard.instantiateViewController(withIdentifier: "secondVC") as? SecondViewController
vc?.loadViewIfNeeded()
// use the vc
// later unset vc variable
vc = nil
for this, you must call your 2ed View controller with 'modalPresent' and background of 2edVC must clear. Then get your data from 2ed VC. with no change. for more information about modalPresent there is the link.
Solution:
You can create a function for it or just insert in viewDidLoad() etc.
Don't forget to change StoryboardID for the chosen view controller (it can be done in your storyboard file in Identity inspector).
// You need to get to your Storyboard and instantiate the needed View Controller
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var graphVC = storyboard.instantiateViewController(withIdentifier: "graphVCID") as? graphVC
// Then call loadViewIfNeeded (don't call loadView()) to load #IBOutlet's etc
graphVC?.loadViewIfNeeded()
// My outlets are loaded with data when these functions are called
graphVC?.viewDidLoad()
graphVC?.viewWillAppear(false)
// Unset the reference to VC
graphVC = nil

SWIFT 3: Segue with navigation controller

I'm trying to send some values from one viewcontroller to another. (all embedded in NavigationController). I could make segue with normals viewcontrollers so in general I understand a segue idea. I've to do that in two different ways and got two different problems.
First way, segue does right but "two times". I mean after segue (which I want) there is another segue to same controller but without navigation controller and without data I would send. The "back" button on last viewcontroller is returning to AlmostViewController.
Here's code:
Second way, Nothing happened,
ErorCould not cast value of type 'RevisionApp.AlmostViewController'
(0x1055d58c0) to 'UINavigationController' (0x107669f18).
Here's code:
For the first Problem, When using embedded in navigation controller you have don't have to create action function when the button is tapped. Navigation controller does it for you. So things you need to do :
Disconnect the function btnTapped from the button using storyBoard.
Delete or comment the function btnTapped(You don't need it).
Problem is line number 18. You are trying to cast AlmostViewController to a UINavigationController. Directly access like this,
let detailController = segue.destination as! AlmostViewController
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("ViewController2") as NextViewController
self.presentViewController(nextViewController, animated:true, completion:nil)

Swift Prepare for segue interrupted by TabBarController

I currently have a storyboard that has a tableview with my data, and I believe I correctly pass that data using the didSelectRowAtIndexPath and the prepareForSegue functions.My problem is that when I select a certain cell my cast becomes incorrect because I have a tab bar controller holding my views to be displayed with this segued information.I want my cast to be:
let destination = segue.destinationViewController as! DownloadViewController
But I am getting an error because the segue is going to the tab bar controller first. This error makes perfect sense to me but I am unsure how to get around it without getting rid of the tab bar controller completely. Here is a picture of my story board to help show the overall flow.
http://imgur.com/7gFKKIZ
Any help is appreciated.
The UITabBarController has an array that contains its connnected viewController, to access e.g. the first one try
let destination = (segue.destinationViewController as! UITabBarController).viewControllers?.first as! DownloadViewController
Instead of using segue, you can use a modal presentation of your desired first tab for display if it works for you.
let displayFirstVC = storyboard.instantiateViewControllerWithIdentifier("newVC") as! UIViewController
self.presentViewController(displayFirstVC , animated: true, completion: nil)
When you instantiateViewControllerWithIdentifier, you have to create a storyboard name for your FirstViewController with name newVC.
You would also need to replace UIViewController with the name you gave your view controller.
More details here.
Instantiate and Present a viewController in Swift

Pass data with segue without displaying screen

I'm trying to achieve passing of data using segue, but without displaying the screen. There are two view controllers in my project and I will name them FirstViewController and SecondViewController.
On FirstViewController, I am using Show Adaptive Segue to pass data using performSegueWithIdentifier. The prepareForSegue method will be called, and recognising the identifier I've set to display SecondViewController.
However, the problem is I do not want to display SecondViewController. There are other things that my users may want to do before heading for SecondViewController.
I'm new to iOS programming, and I only know passing of data with segue. Please do share with me if there are methods to pass data apart from segue.
EDIT: To further elaborate my question. I'm working with TabBarController, and both View Controllers are accessible on the Tab bar. So when I am on SecondViewController with some data already "segue-ed" over from FirstViewController, I can head back to FirstViewController to add more data. At SecondViewController with UIRefreshControl I need the updated data.
If you do the segue in code you can do what you want in a following way
1) Instantiate view controller from the story board
let storyboard: UIStoryboard = UIStoryboard(name: "SecondViewController", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("set_it_in_IB") as! SecondViewController
2) Set the properties you need to set as the view controller is already instantiated
vc.someProperty = "asd"
3) Segue!
viewController.presentViewController(viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?)
Hope that helps!
From your user's perspective, they would not know whether the data is being updated before they segue or not, so it is probably fine to just pass the data with the prepareFoSegue function.
Otherwise, you could try setting a notification to the viewDidLoad on your FirstViewControllerand SecondViewController by
NSNotificationCenter.defaultCenter().addObserver(self, selector: nil, name: updateSecondVCNotification, object: nil)
and posting the notification from the FirstViewController whenever the data needs to be updated using the
NSNotificationCenter.defaultCenter().postNotificationName(updateSecondVCNotification, object: self)
Then on second view controller set the the selector of the addObserver to a string of the name of whatever function you want it to do like "reloadNewData"
func reloadNewData() {
tableView.reloadData()
}
Does this help? Don't forget to set the updateSecondVCNotification as a global string constant at the top of your FirstViewController. Learn more about NSNotificationCenter at https://www.andrewcbancroft.com/2014/10/08/fundamentals-of-nsnotificationcenter-in-swift/
Woo! Notifications! \(^▽^)/
I'm not sure if that would work for you, but you could simply keep the data in memory of your FirstViewController for the time during which the user is still interacting and giving feedback and once it's done, send all the data to the SecondViewController through the segue.

Resources