How to get a ViewController to segue to itself repeatedly. - swift

SWIFT: In my storyboard, embedded in a NavigationController, I have a ViewcontrollerA which needs to either present itself repeatedly OR present ViewcontrollerB based on an if clause.
I've implemented the logic in the prepareForSegue method. I've drawn a segue from ViewcontrollerA to ViewControllerB.
if (someClause == true)
{
let svc = segue.destinationViewController as! ViewControllerA
} else {
let svc = segue.destinationViewController as! ViewControllerB
}
Executing this code results the following error:
Could not cast value of type 'ViewControllerB' to 'ViewControllerA' .
That's because there is no segue from ViewControllerA to ViewControllerA. The segue is from ViewControllerA to ViewControllerB.
Is there a way for one "Button" to have multiple segues? One to ViewControllerA (itself) and one to ViewControllerB. I know this is possible for TableViewCells.
Side note, I have managed to get instantiateViewControllerWithIdentifier followed by a call to presentViewController to do what I want, but that destroys my NavigationStack and TabBar. I DONT want to go this route because it seems like a lot of patch work.

You should create a segue between from ViewControllerA to ViewControllerB, not the button to ViewControllerB. Then do something like:
#IBAction func buttonPressed(sender: UIButton) {
if (someClause == true)
{
// Stay on ViewControllerA
} else {
performSegueWithIdentifier("showB", sender: AnyObject)
}
}
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "showB") {
let _ = segue.destinationViewController as? ViewControllerB
}
}

Related

Make a segue to a tableview controller from a view controller

I am trying to make a segue to a table view controller when a button is tapped in my view controller programmatically. Here is my code:
#objc func editProfileButtonAction(sender: UIButton!) {
print("ButtonTapped")
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
if identifier == "EditProfile" {
var editProfileTableViewController = segue.destination as! EditProfileTableViewController
editProfileTableViewController = self
}
}
}
}
I really could use some help. I also need to make a segue to a collection view controller using a button in the same view controller.
Okay to clarify that. There is no way to create a segue programmatically. Segues are the arrows on storyboard linking from one to another VC. They are called with: performSegue. This calls the function prepare.
If you want to show a new VC when hitting a button (without segue), then you use the present(VC(), animated: true, completion: nil) } inside the button function. The VC is presented modally.
#objc func editProfileButtonAction(sender: UIButton!) {
print("editProfileButtonAction")
present(EditProfileTableViewController(), animated: true, completion: nil)
}
Make sure, that the segue in the Storyboard has exactly the identifier: "EditProfile". Normally I'm writing identifiers with lower letter in the beginning. You also need to prepare for Segue. For example set the delegate:
// Set ViewController class as the delegate of the EditProfileTableViewControllerDelegate protocol
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
if identifier == "EditProfile" {
let editProfileTableViewController = segue.destination as! EditProfileTableViewController
editProfileTableViewController = self
}
}
}
At one point in my coding time, I deleted all my storyboard because of too many error's that I could hardly solve. Now I'm doing it all programmatically. At first it was a bit hard to set up all the view's by myself but after all I'm very glad I'm not using storyboards anymore. For some stuff I need xib's, and for testing storyboard. Just if you're interested: the most iOS programmers are using storyboard, so it's okay if you go on with that.
The advantage of doing it all programmatically is that there are no segue's anymore. So just present, and on navigation VC's push, pop, ...

performSegue to same ViewController from delegate method

I'm trying to perform a segue from ViewController A to ViewController A (same VC). I can do that when I ctrl+drag from a button to the VC and set the identifier ("sameVC" in my case).
When the button is tapped, the segue works as expected. The problem is, I need to call
self.performSegue(withIdentifier: "sameVC", sender: self)
from a delegate. So when the button is tapped, I need to call a function, that has a delegate, like this:
class ViewControllerA: ViewController, MyDelegate {
var mC = MyClass()
override func viewDidLoad() {
mC.delegate = self
}
#IBAction func buttonTapped(_ sender: UIButton) {
mC.myfunc()
}
func success {
// Trying to call delegate
self.performSegue(withIdentifies: "sameVC", sender: self)
}
}
protocol MyDelegate {
func success()
}
class MyClass {
var delegate: MyDelegate?
func myfunc() {
// ...
self.delegate.success()
}
}
When the delegate comes back to ViewControllerA in "success"-function, I want to perform the segue, but the View isn't present anymore, because the segue was called implicit with "buttonTapped"-function.
When the segue isn't going to the same VC, I would just ctrl+drag from ViewControllerA to ViewControllerB, but this isn't possible with only one ViewController (or I don't know how to do this).
Is there any way I can achieve this?
Instead of ctrl+dragging from button, ctrl+drag from ViewController itself, then it will wait for you to call performSegue
And for going from you have more than one viewcontrollers you may want to navigate to, you can assign an Identifier to your viewControllers in your storyboard and use storyboard.instantiateViewControllerWithIdentifier method to instantiate your desired ViewController and present it to the user, e.g. push it on top of current viewcontroller.

Disable textfield in destination view controller

I have two view controllers: ViewController1 and ViewController2.
My objective is, when the segue is triggered if a certain condition in ViewController1 is met a textfield in viewController2 to be disabled.
I have setup shouldPerformSegueWithIdentifier and prepareForSegue and everything works fine, but when i put the condition it crash saying that it found an error unwrapping an optional- the textfield.
my ViewController1 is :
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject!) -> Bool {
if condition1=true{
return true
}
else{
return false
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier=="segue"){
let destVC:ViewController=segue.destinationViewController as! ViewController2
if n==1{
destVC.myTextField.enabled=false
}
}
}
In prepareForSegue method myTextField of ViewController2 is not initialized yet, so thats why you are getting an error unwrapping an optional textField, To solve your crash create one Bool instance inside your ViewController2 and pass its value in prepareForSegue method.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier=="segue"){
let destVC:ViewController=segue.destinationViewController as! ViewController2
if n==1{
destVC.isEnabled=false
}
}
}
Create instance isEnabled inside ViewController2 like this and used it in the viewDidLoad of ViewController2
var isEnabled: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
self.myTextField.enabled = self.isEnabled
}
The views associated with the destination controller are not yet loaded/instantiated at that point.
Create an instance boolean flag on the destination VC and set that in the prepare segue function. Then in viewDidLoad or later in the destination VC check for that switch and disable the text field.
You can set condition at your destination view controller then you can do this
myTextField.userInteractionEnabled = false
Enable and disable userInteractionEnabled of your textfield.

How to know which segue was used using Swift?

I have a main viewController and a detailsViewController. The detailsViewController has 2 buttons. Both buttons are segues back to the main controller but I want to customize the main viewController based on which segue was used. What is the best way to check which segue was used to reach a viewController so that the main viewController can be customized depending on that? - if segue1 leads to the the main viewController then I want label1 hidden. if segue2 leads to the main viewController, then I want label2 hidden.
In Main View Controller create a variable , something like
var vcOne : Bool = true
Now in DetailsViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "segue_one"
{
let mainVC : MainViewController = segue.destinationViewController as! MainViewController
secondVC.vcOne = true
}
else if segue.identifier == "segue_two"
{
let mainVC : MainViewController = segue.destinationViewController as! MainViewController
secondVC.vcOne = false
}
}
Now in MainView Controller
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//Now check here for which segue
if(vcOne)
{
// implement for button one click
}
else
{
// implement for button two click
}
}
Hope it helps you
I'd do something like to check which segue was used. You have to set an identifier to the segue in the storyboard though!
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "yourIdentifier" {
let yourVC = segue.destinationViewController as? yourViewController
//do magic with your destination
}
}
There is a option for setting Identifier for segue. This should be unique identifier. So that you can identify which segue is activated.
Ex:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Identifier1" {
let firstVC = segue.destinationViewController as? FirstViewController
} else if segue.identifier == "Identifier2" {
let secondVC = segue.destinationViewController as? SecondViewController
}
}

Resign First Responder On Push To Detail

I was wondering how to resignFirstResponder whenever I switch to my detailView in the tableView, is this something I can implement in my prepareForSegue or somewhere else.
Here is my prepareForSegue code.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DetailView") {
let VC = segue.destinationViewController as! DetailViewLemon
if let indexPath = self.tableView.indexPathForSelectedRow {
let Make = self.resultSearchController.active ?
filteredTableData[indexPath.row] as String :
tableData[indexPath.row] as String
VC.sentData1 = Make
}
}
}
Any UIView (and UIWindow as well, as it is UIView subclass) has method
func endEditing(force: Bool)
This will resign any current first responder descendant in the hierarchy of the view on which you call this method.
So you can call it on the view of the previous detail view controller or at the whole application's window from the prepareForSegue or any other logic point of your program.