Segue To Same View Controller Programmatically? - ios

Is there a way to segue to the same view controller in Swift? There is an answer for this in Objective-C but I can't convert it to Swift
UPDATE: I was able to push to the same viewcontroller but it immediately errors because it doesn't recognize the objects that were created on the storyboard
let aViewController:myVC = myVC()
self.navigationController!.pushViewController(aViewController, animated:false)
On the Load of the new(same) view controller it errors on the first line:
myText.editable = false;

Set an identifier for your UIViewController in the storyboard. Then instantiate it using that my identifier:
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "someViewController")
If you want to set variables, make sure to cast vc. This example will help you know how many levels deep you are on the same controller:
let vc = storyboard.instantiateViewController(withIdentifier: "rootViewController") as! MyRootViewController
vc.level = self.level + 1

I don't do much in swift, but looking at that answer, using self.navigationController?.pushViewController(viewController, animated:true)
should work.

First you connect your button for reloading with ViewController and give segue identifier a name (for instance "yourIdentifier")
Then you need to use:
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "yourIdentifier"{
self.viewDidLoad()
}
This should help.

Related

How to create a segue to a Table View Controller Scene directly in a swift class file?

I am implementing FB Login. I have instantiated the FBSDKLoginButton() and added it to view directly from my ViewController.swift file (created and presented through the source code).
Normally I present a view modally by dragging and connecting the button to the new view in Interface Builder. However this button does not exist in my storyboard. How can I complete this task, but directly from my ViewController.swift file.
You can add manual segues from one ViewController to other ViewController.
In your FirstViewController in storyboard :
Connect the segue.
Then select the connected segue and add Identifier:
Now you can use:
self.navigationController?.performSegue(withIdentifier: <The Identifier name>, sender: <If you want to send some data with it>)
you can use prepare(for segue: UIStoryboardSegue, sender: Any?):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
to send data to the SecondViewCntroller.
Hope this helps.
Direct segue needs a connection from UI object to other view-controller. Rather segue, you can use pushViewController:
let sb = UIStoryboard(name: "Main", bundle: Bundle.main)
if let viewcontroller = sb.instantiateViewController(withIdentifier: "storyboardIdentifier") as? YourViewController {
self.navigationController?.pushViewController(viewcontroller, animated: true)
}

Calling function with argument from segue

I have a FirstVC with table view with segue to another SecondVC where i pass the name of pressed cell. In SecondVC i have another tableview which i want to populate with data. I have a function called gettingUrls() which is pulling data for my table view:
DataService.instance.mainRef.child("Folders").child("\(folderName)").observeSingleEvent(of: .value) { (snapshot: DataSnapshot) in...}
where "folderName" is the value from FirstVC. This function is implemented into "pull to refresh feature" and it works great. However when i try to run the function itself in viewDidLoad it keeps crashing the app because of empty folderName value. I just can't understand why at this point the value from segue is available in refresh function and not in viewDidLoad.
Here is the code of segue:
let detailVC = self.storyboard?.instantiateViewController(withIdentifier: "DetailVC") as! DetailVC
self.navigationController?.pushViewController(detailVC, animated: true)
self.present(detailVC, animated: true, completion: nil)
detailVC.folderName = fileName
How can i run the function in viewDidLoad?
You're presenting the DetailVC's view before you've set its folderName property. The view has loaded but it doesn't yet have a folderName so the program crashes. You should place the line detailVC.folderName = fileName before you present the DetailVC.
You also don't need both the 2nd and 3rd lines - either present the new view controller or push it onto the navigation stack, not both.
You should write code with segues to push viewControllers like following not with navigationController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "Verification") {
let vc = segue.destination as! MyViewController
vc.delegate = self
vc.property = value
}
}
So with #haarismuneer help, it was enough to pass the variable before initializing SecondVC:
detailVC.folderName = fileName
self.navigationController?.pushViewController(detailVC, animated: true)

How can I pass data to the next view controller when it is loaded programmatically?

Suppose I have three view controllers in a Main.storyboard. Two of the three, vc_login and vc_studyDesc load the other view controller using a UIButton with 'present modally' option.
The other one vc_signup has a UIButton, which may go back to the previous controller. To implement this, I used the following methods:
vc_studyDesc has an identifier of studyDesc; I let it pass its identifier to vc_signup. In the same way, vc_login has login as an identifier.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if sender as! UIButton == qnaSignUp {
let signup = segue.destinationViewController as! vc_signup
signup.latestVC = "studyDesc"}}
This one is in the UIViewController class for vc_signup. By referencing a string latestVC, the method determines which VC to move on.
#IBAction func backBtnClick(sender: UIButton) {
print("latestVS: \(latestVC)")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier(latestVC)
vc.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
print("check check")
self.presentViewController(vc, animated: true, completion: nil)}
The problem I have is that the app gets terminated when vc_studyDesc is called by vc_signup. I found that this is because I missed a significant variable which must be loaded in vc_signup.
vc_studyDesc has some data to be referenced from Firebase when it is loaded. I did this by loading a variable postID from the prior vc to vc_studyDesc; which is vc_list.
So I just saved postID using NSUserdefaults.standardUserDefaults(). It is solved but I'm wondering if there's any way to pass data using the way I used in vc_signup.
As far as I see, I cannot find any way to pass the data into vc_studyDesc.swift; for the vc is chosen by its identifier..
Can I pass the variable I want in the way I want?? And adding tags would be appreciated!
So there are a couple problems with this design.
When you instantiate a viewController you are creating a new instance of that class, and presenting it adds it to the stack. Think of the stack like a deck of cards, you start with one card and then add or remove them, the top card being the visible vc. When you are going back to studyDesc you are instantiating and presenting it so you will have 3 VCs in your stack, of which two are studyDesc (the one you started with and the one you add when you try to go back)
To remove a VC from the stack you can use
dismissViewController(animated: true, completion: nil)
or if you have the VCs in a navigation controller you can use
popViewControllerController(animated: true, completion: nil)
in terms of passing information between viewControllers, if the info is in the VC you use to present your new controller you can use prepareForSegue like you already have. To pass information back you should use a delegate pattern. So to implement a delegate pattern in this case you would do the following:
Declare a protocol (not inside your classes, above there but below your import's)
protocol SignUpDelegate {
signInCompleted(infoToPass: AnyObject)
}
Then have your studyDesc class conform to this protocol and implement the function signInCompleted
StudyDescVC: UIViewController, SignUpDelegate {
func signInCompleted(infoToPass: AnyObject) {
// do what you want with the info here
}
}
Then in your signUpVc add a var delegate (which will be used to call the signInCompeleted function)
class SignInVC: UIViewController {
var delegate: SignUpDelegate!
func finishedSigningIn() {
delegate.signInCompleted(infoToPass: //yourinfo)
self.dismissViewControllerAnimated(true, completion: nil)
}
And then in your prepareForSegue set the delegate
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if sender as! UIButton == qnaSignUp {
let signup = segue.destinationViewController as! vc_signup
signup.delegate = self
}
}
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier(latestVC) as! YOUR_VIEW_CONTROLLER_NAME
vc.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
vc.name = "Andrew"
print("check check")
self.presentViewController(vc, animated: true, completion: nil)
//set a variale or property to your viewController
class YOUR_VIEW_CONTROLLER_NAME: UIViewController {
var name: String?
}

Unwind segue hides UITabBar using Swift

Good afternoon,
I'm trying to perform an Unwind segue from a ViewController to the parentViewController, but for some reason it's working but instead of showing the parentViewController wit the UITabBar (because everything is inside a TabBarController) it's showing the parentViewController without the UITabBar.
The question is: How can I perform an "unwind segue" and make visible the UITabBar in my parentViewController?
I perform the first segue (from parent to ViewController) using a segue "present modally" with "current context", and I use this because I need to show the UITabBar also in the ViewController.
That's my first segue (from parent to ViewController):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "showPost" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let navVC = segue.destinationViewController as! UINavigationController
let childVC = navVC.viewControllers.first as! PostViewController
childVC.id_post = posts[indexPath.row].idPost
}
}
}
And that's my unwind segue:
#IBAction func backToPosts(segue:UIStoryboardSegue) {}
Here you are and screenshot of my Storyboard:
Thanks in advance,
Regards.
Try in the viewDidLoad tabBarController.tabBar.hidden = false
have you tried theController.hidesBottomBarWhenPushed
If someone is having the same problem:
I removed the NavigationController after the TabBarController.
Regards

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