Calling custom function inside UIStoryboard-instantiated UIViewController (Swift) - ios

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)

Related

Swift 2 self.presentViewController vs segue for simple navigation

I am new to iOS Development and I am using swift2 to develop a simple web application whereby I am unsure of the behaviour of self.presentViewController.
In my MainViewcontroller I have the following codes to redirect user to login viewController
let storyboard = UIStoryboard(name: "Main", bundle: nil);
let signinViewController = storyboard.instantiateViewControllerWithIdentifier("SigninViewController") as! SigninViewController;
self.presentViewController(signinViewController, animated: true, completion: nil);
This set of codes work the way I want it to, which will redirect the user to signin page upon starting the application.
However in android development, I have to do a "finish();" to destroy my current stack, and I am unsure whether if I have to follow similar procedure in iOS Development.
Next, I have done some research on self.presentViewController versus segue as followed in the given article
UIStoryboardSegue versus presentviewcontroller?
So am I save to say that my approach in redirecting users from (Main_VC to SignIn_VC) is correct?
Your code is correct. You should not destroy presenting view controller in any way, it needs to be there when you get back from presented view controller.
If you do not plan to ever return the previous controller, you can simply replace it with new view controller as your window's (or navigation controller's) root. Since you are presenting sign in controller, this is probably not what you might want to do, just mentioning in for sake of completeness

Creating multiple segues from one UIButton to the same view controller or another

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"):

Push Notification open specific screen in TabBarController NavigationController revealViewController

Here is what I am trying to do.
When I receive the push notification and I tap I want to show a specific screen in my app. I found a lot about it but I am having trouble due to the complexity of the structure of my application.
Here is how the app is structured:
LoginViewController
RevealViewController (https://github.com/John-Lluch/SWRevealViewController)
UITabbarController
NavigationController
ViewController (This is a table view)
DetailViewContorller
I want to pass some arguments to the DetailViewContorller so I can make sure I get the right results when opening the screen.
Here is the screenshot of my app structure
application Folow
With the following code in my AppDelegate:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tb = storyboard.instantiateViewControllerWithIdentifier("TabBarVC") as! UITabBarController
tb.selectedIndex = 1
window?.rootViewController? = tb
I have managed to get to the tabbar when tapping on the notification but I am not happy with the results. I am still having the following issues:
the revealViewController is nil so I am not able to open my setting panel
I still don't get to the DetailViewController which is at the bottom of my view hierarchy
Any hint will be appreciated.
I had a similar issue although my flow was a bit different. I ended up handling Push Notification event (when user taps on it) and storing the object at the app delegate level. In each view controller that appeared after that (in ViewDidLoad() method) I would check for that object and figure out whether to redirect the flow to the next view controller. To help with this, my notifications had a type associated with them. Unfortunately, I was not able to find a better solution.
P.S. It also appears like you're instantiating View Controllers in code and I was using Storyboards. However, the basic idea is the same. I ended
#MK_Dev, Thanks for your suggestion but I was looking for something easier to manage.
This has actually helped me.
Get top most UIViewController
Here is what I did:
if var topControl = UIApplication.sharedApplication().keyWindow?.rootViewController {
while let presentedContreller = topControl.presentedViewController{
topControl = presentedContreller
}
if topControl.childViewControllers[0].isKindOfClass(MyCustomClassVC) {
// Check if the user is already on the VC we are trying to open
let chatController = topControl.childViewControllers[0] as! MyCustomClassVC
// ... any additional code you need to add here ...
}
}

Programmatically moving the user between view controllers in Swift

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)

Performing a Segue from a UIView programmatically

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);

Resources