Depending on the user's action, I need to move the user from one view controller to another depending on if they complete a task by time or complete a task by pressing a button. Both call the same method completeSession()
I've gone into the storyboard and added a Storyboard ID for each screen that is the same as the view controller class. So for this question, class JournalViewController has a storyboard ID of JournalViewController, same with SecondViewController
func completeSession() -> Void {
... some other stuff, unrelated ...
let journalViewController = self.storyboard?.instantiateViewControllerWithIdentifier("JournalViewController") as ViewController
self.presentViewController(journalViewController, animated: true, completion: nil)
}
This isn't working and causing my app to crash with a reason: Storyboard <UIStoryboard> doesn't contain a view controller with identifier JournalViewController, yet JournalViewController.swift contains:
class JournalViewController: UIViewController, UITextView Delegate {
Any idea how to push from SecondViewController to JournalViewController without error?
I think you can probably check the post here:
What is a StoryBoard ID and how can i use this?
So, you have to understand how you can connect your code with your graphics. Before Storyboard comes out, we use NSBundle to load the graphics. So, the same thing here is how you are going to load your graphics. Because Storyboard does not simply just contain one screen. So, you will have something to identify them. That's why we need that.
To answer my own question, this code worked, the missing piece was going into Storyboards and giving each item a storyboard ID.
instantiateViewControllerWithIdentifier relies on your storyboard ID to grab it successfully so that the app knows where to push the user to.
I hope that helps.
let journalViewController = self.storyboard?.instantiateViewControllerWithIdentifier("JournalViewController") as JournalViewController
self.presentViewController(journalViewController, animated: true, completion: nil)
Related
I am having a weird issue where my app crashes when I am trying to push a new view controller. I have set up a swipe gesture and want to segue to another view controller when a swipe is detected. When I run these 2 lines of code ...
let viewController:ViewController = ViewController()
self.navigationController?.pushViewController(viewController, animated: true)
The app crashes not specifically on either of those lines of code but rather in my ViewController class when in my viewDidLoad method I run this piece of code...
imageView.layer.masksToBounds = true
If I comment that out it crashes when I set the auto-correction type of my textField. What am I doing wrong?
First place I look when the view immediately crashes is in the Outlets for that ViewController in InterfaceBuilder. I look for anything that shows up with an exclamation mark. That usually means I renamed an outlet or broke a connection somehow. Delete anything broken by pressing the little x by the item that's messed up. I'll attach a photo so you can see.
It seems you're loading a ViewController that exists in storyboard with
let viewController:ViewController = ViewController()
which will result in nil outlets , so you have to use
let viewController = storyboard.instantiateViewController(withIdentifier: "VCID") as! ViewController
and give that vc a storyboard identifier like VCID
I think I have solved the issue but it has a weird side effect. Instead of using the line of code in #Sh_Khan's answer, I used ...
let viewController = nav?.storyboard!.instantiateViewController(withIdentifier: "mainVC") as! ViewController
The variable nav is equal to the navigation controller of the current view-controller. This seems to work without any hiccups but for some reason the back button does not disappear from the navigation controller after the segue is preformed. Does anybody know a solution to this, if so leave a comment and I will update my answer.
EDIT:
Another issue is that it wipes everything changed on that ViewController by the user clear. Is there another way to instantiate a ViewController without clearing it?
Follow what #Sh_Khan has said and in addition to that make sure that the view that you are making the push segue from is embedded in a Navigation controller.
i'm fairly new to swift, so please bear with me.
right now my problem can be broken down to this:
I have one Test View Controller that can display my 'Test' object by showing the description and the title. I also have an array of Test objects. In the top right hand corner, there is a 'skip this test' button, and if the user clicks on it, the viewcontroller will segue to itself, but change the Test object that is being displayed, e.g. its just basically looping through an array of Tests. I have changed the prepare for segue methods accordingly to push the data through the view controllers.
However, I want to be able to move to a completely different ViewController (lets just call it FinalViewController) if I have reached the last Test in my Test array.
Now this is the part that I can't fix.
I would like to create a segue directly from the 'skip test' button, only that it segues to a different view controller, depending on a certain condition. However, as i tried creating a segue in IB by right clicking on the Button and pulling it to the FinalViewController, it erased my previous segue I had for that button.
Does anybody know if there is a fix for this problem? thank you!!!!
However, as i tried creating a segue in IB by right clicking on the
Button and pulling it to the FinalViewController, it erased my
previous segue I had for that button
Actually, you don't want to do that, instead, you should drag from the controller itself, not from the button because if your segue has been created based on a button, tapping on it should always perform it and this is NOT what you want.
After creating a segue from the ViewController, you can -programmatically- call performSegue method and handle what data should be passed to the next viewController by implementing prepareForSegue method.
For more information, check my answer to know how to create multiple segues with identifiers and work with them.
EDIT:
If you want to push to the same current ViewController, performSegue method would not be the optimal solution. You should instead push/present to same ViewController it self:
class ViewController: UIViewController {
var myString: String?
override func viewDidLoad() {
super.viewDidLoad()
// here we go
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sameViewController = storyboard.instantiateViewControllerWithIdentifier("ViewControllerStoryboardID") as! ViewController
sameViewController.myString = "the value of the new myString"
navigationController?.pushViewController(sameViewController, animated: true)
print(myString)
}
}
Probably, you don't want to implement it in viewDidLoad, it's just for demonstration purpose.
Make sure that the ViewController has a storyboard ID (in code snippet, I assume it is "ViewControllerStoryboardID"):
I think my problem is best expressed by first giving an outline of what I'm trying to accomplish and then giving my implementation, followed by the problem I've ran into.
Goal
I'm attempting to make a profile page within my iOS app that can be instantiated from the Storyboard, given a user ID, and then fetch all the meta data from the server.
Implementation
In my storyboard, I have designed the ViewController and linked the ImageViews, buttons et cetera as #IBOutlets. The user's (person using the app.) homepage is instantiated by the Storyboard, but the rest are pushed in by code. In order to grab the data, I have a function loadDataForID(ID: Int)
Now, the problem I have is that #instantiateViewControllerWithIdentifier(String) returns a UIViewController that I cannot upcast to my ProfileViewController, in order to call the data fetching function.
So, my next thought was to manually create the ProfileViewController, call the helper function and then push the view, but then I ran into another problem: since all the views are #IBOutlets, and this controller wasn't instantiated by the Storyboard, they're all nil references.
As I'm new to iOS development, I'm almost certain there's a better way to implement this, but I'm completely stuck; I don't know where to go from here. Is there a way around these issues or should I do things a different way?
You can cast instantiateViewControllerWithIdentifier(String) as ProfileViewController as shown into below code:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let profileVC = storyboard.instantiateViewControllerWithIdentifier("ProfileViewControllerID") as! ProfileViewController
//Now you can access property of ProfileViewController here
self.presentViewController(profileVC, animated: true, completion: nil)
I'm trying to create a custom UIView that will, when tapped, segue to a new view controller. I'd like to do this programmatically rather than in Interface Builder. How do I get a reference to the destination view controller when I'm doing this? I assume I don't just create one and set it as the next view or something, so where does the reference come from? Since when it's done in the storyboard you simply choose where you want the segue to have as the destination, it's not an issue there, however programmatically I don't understand where that reference comes from.
I'm doing this in Swift as well. I don't think that really makes a big difference, but it might change something.
I tried using a UIView with a tapGestureRecognizer added, which then performed the segue when tapped, however I was getting an unrecognized selector error.
If you declared your UIViewController in storyboard you have to set its Storyboard Id, and then, instead of performing segue you can use something like this (didn't run it, but done exact the same thing in obj-c, so I think it will do well):
let storyboard : UIStoryboard = UIStoryboard(name: "myStoryboardName", bundle: nil);
let vc : MyUIViewController = storyboard.instantiateViewControllerWithIdentifier("myVCStoryboardID") as MyUIViewController;
self.presentViewController(vc, animated: true, completion: nil);
I have a problem again. I work with storyboard in Xcode 6 with Swift as programming language. Before I want to present a view (with a view controller) on starting my app I want to test the internet connection and my server connection. If both connections are available I want to present a view1 and if not I want to present a view2. But I don't want to show a view with a spinner while checking the connection. So I thought I can manage it over the AppDelegate class. In the function func application() I want to decide which view (view1 or view2) is loaded at first. But for this solution I have to instantiate two view controllers that are connected to my two views in storyboard. I don't know if it is possible.
So my question, is it possible to instantiate these two specific storyboard view controllers in my AppDelegate class? And if it is possible, how can I do this by code?
If it is not possible, how can I solve my problem? At the moment I always show a view controller with a spinner (view0) and if connection is available I go to view1 and if connection is not available I go to view2 from my view0 controller like this:
override func viewDidAppear(animated: Bool) {
//some code
self.presentViewController(view1, animated: true, completion: nil)
//some other code
}
You can load a specific view controller from a storyboard with this call:
let viewController = self.window?.rootViewController?.storyboard?.instantiateViewControllerWithIdentifier("SomethingViewController") as UIViewController
self.window?.rootViewController = viewController
But to be honest, it doesn't seem good to make the user wait with no information while you do the connection tests.
It would be better to show a temporary view controller during the waiting, unless those tests are really fast :)
Edit: corrected the code.
It's a hackish solution, as it will load a new rootViewController after initializing the original one I suppose. But it should work.
A more correct alternative would be creating the project as "empty application" and loading the storyboard by code, directly in the controller you want.