What is the difference between using instantiateViewControllerWithIdentifier and performseguewithidentifier? - ios

Both methods allow me to present a new view controller (one by calling presentviewcontroller), so I don't understand the difference between the two and when I should use them.

They both reference storyboard related identifiers. The main difference is one (performSegueWithIdentifer) instantiates an object based on a segue's end (where the segue points to), while the other (instantiateViewControllerWithIdentifier) instantiates a unique VC based on the VC's identifier (not the segue).
You can have multiple segue's with the same identifier in different places in the storyboard, while VC's in a storyboard cannot have the same identifier.

performSegueWithIdentifer and instantiateViewControllerWithIdentifier both are used to move from one viewController to another viewController.
But there is so much differences....
The identifier of the 1st case defines a segue like push, modal, custom etc which are used to perform a specific type of transition from one VC to another VC.
eg.
self.performSegueWithIdentifier("push", sender: self);`
where "push" is an identifier of a push segue.
The identifier of the 2nd case defines a VC like myViewController, myTableViewController, myNavigationController etc. 2nd function is used to go to the specific VC ( with identifier.) from a VC in the storyBoard.
eg.
var vc = mainStoryboard.instantiateViewControllerWithIdentifier("GameView") as GameViewController;
self.presentViewController(VC, animated: true, completion: nil) ;
where "GameView" is the identifier of GameViewController.
Here a instance of GameViewController is created and then the function presentViewController is called to go to the instantiated vc.
For the 1st case with the help of segue identifier u can pass one are more values of variables to the next VC.
eg.
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!)
{
if (segue.identifier == "push")
{
let game = segue.destinationViewController as GameViewController
game.value = self.myvalue // *value* is an Int variable of GameViewController class and *myvalue* is an Int variable of recent VC class.
}
}
This funcion is also called when self.performSegueWithIdentifier("push", sender: self); is called to pass the value to GameViewController.
But in 2nd case it possible directly like,
var vc = mainStoryboard.instantiateViewControllerWithIdentifier("GameView") as GameViewController;
vc.value = self.myvalue;
self.presentViewController(VC, animated: true, completion: nil) ;

Related

How to pass values from a Pop Up View Controller to the Previous View Controller?

So In my 1stViewController I have this code:
#IBAction func colorDropdown(_ sender: Any) {
self.popUpColorPicker()
}
func popUpColorPicker() {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ColorPicker") as! ColorPicker
self.addChildViewController(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParentViewController: self)
}
Which would pop up the 2ndViewController. Upon dismissing the Pop Up 2ndViewController, I'd like to retrieve the values I entered and use it in my 1st View Controller.
You can achieve this by either using delegate or completion handler.
Just create a delegate to handle your data on dismissing the second VC.
**
OR
**
Write a completion handler closure to get back those values in your first view controller.
Suppose A & B are two controllers and you first navigated from A to B with some data. And now you want to POP from B to A with some data.
Unwind Segues is the best and recommended way to do this.
Here are the steps.
Open A.m
define following method
#IBAction func unwindSegueFromBtoA(segue: UIStoryNoardSegue) {
}
open storyboard
Select B ViewController and click on ViewController outlet. press control key and drag to 'Exit' outlet and leave mouse here. In below image, selected icon is ViewController outlet and the last one with Exit sign is Exit Outlet.
You will see 'unwindSegueFromBtoA' method in a popup . Select this method .
Now you will see a segue in your view controler hierarchy in left side. You will see your created segue near StoryBoard Entry Piont in following Image.
Select this and set an identifier to it. (suggest to set the same name as method - unwindSegueFromBtoA)
Open B.m . Now, wherever you want to pop to A. use
self.performSegueWithIdentifier("unwindSegueFromBtoA", sender: dataToSend)
Now when you will pop to 'A', 'unwindSegueFromBtoA' method will be called. In unwindSegueFromBtoA of 'A' you can access any object of 'B'.
That's it..!
you can always use unwind to do some stuff upon unwinding
declare a IBAction in your first vc
var color: UIColor!
#IBAction func unwindToCheckout(segue: UIStoryboardSegue) {
//do some stuff with color
}
then create exit segue for popout viewcontroller
then you can dismiss popout like this
self.performSegueWithIdentifier("unwindToVC1", sender: selectedColor)
then in prepareForSegue
if segue.identifier == "unwindToVC1" {
(segue.destinationViewController as! FirstViewController).color = sender as! UIColor
}
also you can create delegate to reach fistviewcontroller and do some stuff which is way easier to do

Cant use Functions in one file in another

I created a file called "Util.swift" and it has a class "class VC: UIViewController" and has a 2 functions:
Next(segue: String) {
performSegueWithIdentifier(segue, completion: nil)
}
Back() {
dismissViewControllerAnimated(true, completion: nil)
}
So basically, the functions just tell the current viewController to go to the next View or go back to the previous view.
However, in another file, I have an IBAction which is attached to a button and in that action I call the function "Back" in the Util file by doing this:
#IBACTION func ~~~ {
nextVC = Util()
nextVC.back()
}
However, when I click the button, it doesn't do anything.
When I try to connect another button to an action that calls the "next" function in the Util file by doing the same thing and putting in the segue indetifier parameter, it says SIGABRT error: no segue identifier called "xxx".
Can anyone help me? Should I simply use XIB and not use segues?
You have to initialize the UIViewController either with storyBoard or with XIB. If you are doing with factory init() method then it doesn't do anything for you; that means, that is not a viewController which is associated either with storyBoard or XIB. So all you need to do is instantiate the viewController with either options. Before that you need to set an identifier for the viewController to instantiate it.
let storyBoard = UIStoryBoard(name: "MainStoryBoard", bundle: nil)
let vc = storyBoard.instanstiateViewControllerWithIdentifier("YOUR_IDENTIFIER") as! Util
//call your Next method like this
vc.Next(segue:"identifier")
Please refer the document
Apple Doc
In order to use segues, the view controller instance needs to be associated with a Storyboard. In order to be associated with a storyboard, a view controller instance either needs to be the result of a segue or instantiated from a storyboard via instantiateViewControllerWithIdentifier.
When you create an instance of Util via Util() you have a view controller instance that isn't associated with a storyboard and isn't actually presented on screen.
As a result, when you try and perform a segue, you get an error since the segue can't be found.
Also, when you try and dismiss the view controller in back() you are trying to dismiss a view controller that isn't presented.
I am not sure why you want to wrap two fairly simple functions inside next and back, but you can do this using a superclass for all of your view controllers and have this superclass implement your next and back functions:
class MyViewContollerSuperclass: UIViewController {
func next(segue: String) {
self.performSegueWithIdentifier(segue, sender: self)
}
func back() {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Then you actual view controller would be declared as:
class MyActualViewController: MyViewContollerSuperclass {
#IBACTION func ~~~ {
self.back()
}
}

How can I use my action and programmatically transition to a view controller as defined in the storyboard?

I have a sent Action, as follows:
#IBAction func showSettings(sender: AnyObject) {
let settingsPicker = SettingsViewController()
settingsPicker.setDelegate(self)
let navigationController = UINavigationController (rootViewController: settingsPicker)
self.presentViewController(navigationController, animated: true, completion: nil)
}
The method creates a controller, sets a reference to the delegate, and creates a navigation controller.
All this works, however the widgets defined in the story board do not appear. The SettingsViewController should manage a ui which is defined in a story board. I presume becuase I create it programmatically none of the widgets appear. The SettingsViewController does not programmatically create widgets, the are declaratively defined in the story board.
If I link (in the storyboard) the two controllers with a segue, then the widgets appear, but my action is not being used.
How can I use my action and present the view controller / ui as defined in the storyboard?
When you create a segue between your UIViewControllers, you should define an identifier, eg: "settingsSegue".
In your code you can then perform that segue by calling the segue with the identifier:
#IBAction func showSetting(sender: AnyObject) {
performSegueWithIdentifier("settingsSegue", sender: nil)
}
To set up the SettingsViewController you should implement the following:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if let settingsController = segue.destinationViewController as? SettingsViewController {
settingsController.delegate = self
}
}
Interacting with Storyboard and Segues
If you want to invoke a segue through code, see Laffen's answer.
If you want to create a view controller that's defined in your storyboard and then display it programmatically, use instantiateViewControllerWithIdentifier to create a new instance of your view controller, then display it to the screen as desired (present it modally, push it onto your navigation stack, or whatever you want to do.)

Passing information between UICollectionViewControllers through unwind segues

I have two UICollectionViewControllers and the first one uses a push segue to get to the second one. The problem I'm having is passing information back to the first controller when the back button (the one that gets added automagically) is pressed in the second controller. I've tried using the segueForUnwindingToViewController, and canPerformUnwindSegueAction override functions, but no dice. I need to be able to access both view controllers so I can set some variables. Any ideas?
Here is an example with two view controllers. Let's say that the names of the two view controllers and ViewController and SecondViewController. Let's also say that there is an unwind segue from the SecondViewController to the ViewController. We will pass data from the SecondViewController to the ViewController. First, let's set the identifier of this segue by opening the document outline and selecting the unwind segue. Then open up the attributes inspector and set the identifier to "unwind".
SecondViewController Code:
class SecondViewController: UIViewController
{
override func prepareForSegue(segue: UIStoryBoardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
if let destination = segue.destinationViewController as? ViewController {
if identifier == "unwind" {
destination.string = "We Just Passed Data"
}
}
}
}
}
ViewController Code:
class ViewController: UIViewController {
var string = "The String That Will Be We Just Passed Data"
#IBAction func unwindSegue(segue: UIStoryBoardSegue) {
}
}
It sounds like you are trying to intercept the back button, there are many posts for this on SO, here are two:
Setting action for back button in navigation controller
Trying to handle "back" navigation button action in iOS
In practice, it is more clear to return state in closures (more modern), or delegates.

transitioning from one view controller to another using a button

So, I created a login page with basic logic. If username and/or password are empty, it displays an error message. If they're full, then it transitions to the next page (home). I created a second ViewController on the storyboard, and created a SecondViewController". I then defined the respective ViewController class to "SecondViewController".
On the first ViewController.swift file, i used this code:
func transition(Sender:UIButton!)
{
let secondViewController: SecondViewController = SecondViewController()
self.presentViewController(secondViewController, animated:true, completion:nil)
}
When I tested it out however, pressing the login button (when both the username and password are filled) transfers me to a black screen instead of the second View Controller. Any ideas on what to do?
If you want the view to contain things added to it on the storyboard, you could give it a Storyboard ID (a couple of boxes below where you set the class of the view controller in the storyboard).
If you give it for example the ID "secondVC" you can then create it using the following:
let secondViewController = storyboard?.instantiateViewControllerWithIdentifier("secondVC") as? SecondViewController
You can't initialize a view controller with just the default init method.
You should probably create a view controller scene in your storyboard, add a unique identifier on it, instantiate it using instantiateViewControllerWithIdentifier:, and then display it like you are doing.
You'll want to make a segue between the view controllers in your Storyboard, and call self.performSegueWithIdentifier().
Or you can give your `UIViewController an identifier and present it programmatically too:
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let secondViewController storyboard.instantiateViewControllerWithIdentifier("") as? SecondViewController
if let secondViewController = secondViewController {
self.presentViewController(secondViewController, animated:true, completion:nil)
}
There are basically three ways to do this
1)Creating segue in storyboard,though it will only work if you have single segue from that item
2)using prepareforSegue and performSegue Methods in your presenting view controller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "YourIdentifier" {
let controller = segue.destinationViewController as!secondViewController
}
}
Then use this in your IBACtion
performSegueWithIdentifier("YourIdentifier", sender:sender)
3)(Recommended One)
let controller = self.storyboard?.instantiateViewControllerWithIdentifier("ContactsVC")! as! ContactsVC
self.presentViewController(controller, animated:true, completion:nil

Resources