How to navigate between tabs "TabBarController" and transfer data between them? - swift

this code works almost as it should, but it opens a second window on top of the main one, and not separately. How do I programmatically navigate to another view controller?
let tableVC = self.storyboard?.instantiateViewController(withIdentifier: "SaveTableViewController") as! SaveTableViewController
tableVC.titleText = alert.textFields![0].text ?? "Test"
tableVC.tabBarController?.selectedIndex = 1
//self.tabBarController?.showDetailViewController(tableVC, sender: self)
//self.present(tableVC, animated: true, completion: nil)

Your tabBarController have a viewControllers array. If you want to show a specific ViewController programmatically you could set the selectedViewController attribute of your tabBarController to an element out of the viewControllers array...
For more detail: https://developer.apple.com/documentation/uikit/uitabbarcontroller/1621172-selectedviewcontroller

Related

Transition from a sign in ViewController to a UITabBarController

So I am trying to transition from my sign in viewcontroller to my tabbarcontroller, after a successful login.
When I enter my login details and press the sign in button, I am redirected to the Appdelegate page with a signal SIGABRT error.
I tried using this code in my viewcontroller:
let mainPage = self.storyboard?.instantiateViewController(withIdentifier: "CustomViewController") as! CustomViewController
self.present(mainPage, animated: true, completion: nil)
What's in CustomViewController? If you're instantiating that one directly as a ViewController instead of as a UiTabBarViewController, I'm thinking you will need to add the Sub ViewControllers for each one of the Tabs manually. But it's difficult to be sure without looking at what you have in CustomViewController.
Have you tried to set the application's rootViewController to the UITabBarController instance?
For example, this would set application's rootViewController to the tab bar controller:
let mainPage = self.storyboard?.instantiateViewController(withIdentifier: "CustomViewController") as! CustomViewController
UIApplication.shared.keyWindow?.rootViewController = mainPage

How to instantiate a view controller programatically, without storyboard

Is there a way to instantiate a view controller programatically without using storyboard identifier. I want to push CNContactPickerController into my root view controller .
let controller = CNContactPickerViewController()
controller.delegate = self
navigationController?.present(controller, animated: true, completion: nil)
i did this but in contactPicker (delegate) i push a VC from storyboard where i save what info i want from that specific contact.
The problem: when i pop the last view controller i want to go on the CNConctactPickerControllerView but i go on the first view controller
i tried with dismiss but nothing happens..
The problem with doing this is that NONE of the UI for your view controller is created. What you are doing is simply instantiating an instance of the class. None of the corresponding UI is created, also your IBOutlets will be nil.
You have 2 options, either you use Interface builder and instantiate from the Nib or Storyboard, or you create ALL your UI manually in code.
For the sake of resuability you could create a static method on CNContactPickerViewController to handle the storyboard instantiation for you. See the following:
class CBContactPickerViewController: UIViewController {
static func fromStoryboard() -> CNContactPickerViewController {
return UIStoryboard(name: "foobar", bundle: nil).instantiateViewController(identifier: "CNContactPickerViewController") as! CNContactPickerViewController
}
}
You can then utilise this as follows:
self.present(viewController: CNContactPickerViewController.fromStoryboard(), animated: true, completion: nil)

Dynamic Popups in Swift on label word selection

I'm looking for a way to show a dynamically show a popup within a view controller when a user selects a particular word within a label.
For example
Click here for a link, click here for another link
The label text is pulled from a database so is dynamically added based on the content a user is viewing, i was hoping to use the URL schemes within Swift to show the correct popup depending on what a user selected, but when i add the following within app delegate the popup shows within a separate view controller and not as a pop up view controller.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navVC = storyboard.instantiateViewControllerWithIdentifier("glossaryPopupID") as! UIViewController
self.window?.rootViewController?.presentViewController(navVC, animated: true, completion: nil)
return true
When the popup is close the screen behind is now blank rather than showing the original view controller.
SO my question is, whether this is the best way to achieve this as im not sure its best practice to used URL links within an app to link to other parts of the same app, or is there another way i am missing.
Think i have resolved this now, using the following;
let storyboard = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("test") as! ViewController
let popOverVC = UIStoryboard(name:"Main", bundle: nil).instantiateViewControllerWithIdentifier("sbPopUpID") as! PopUpViewController
storyboard.addChildViewController(popOverVC)
popOverVC.view.frame = storyboard.view.frame
storyboard.view.addSubview(popOverVC.view)
popOverVC.didMoveToParentViewController(storyboard)
self.window?.rootViewController?.presentViewController(storyboard, animated: true, completion: nil)

Swift - How to pass UInavigationController and also pass variables

What is the best way to pass a UInavigationController and also pass variables to a new viewController. I know how to do one or the other but not both at the same time. Thank you in advance
this is my current code
func(){
let vc = storyboard?.instantiateViewControllerWithIdentifier("messagesViewController") as! UINavigationController
let posts = self.postList[indexPath.row]
//this is the var that i want to past
//vc.previousViewMessageId = posts.postKey
self.presentViewController(vc, animated: true, completion: nil)
}
If I understand you correctly, you have a view controller that can present a second VC. And this VC is embedded in a UINavigationController. What you don't know how to do, is to pass data from the first VC, to the navigation controller, then to the second VC.
Here is a brute force solution. It's not beautiful, but it works anyway.
Make your own UINavigationController subclass:
class DataPasserController: UINavigationController {
var previousViewMessageId: SomeType?
override func viewDidLoad() {
if let vc = self.topViewController as? YourSecondViewController {
vc.previousViewMessageId = self.previousViewMessageId
}
}
}
Now you can add a navigation controller in the storyboard, set its class to DataPasserController, and connect the second VC to it as its root view controller.
Now suppose you have got an instance of DataPasserController by calling instantiateViewControllerWithIdentifier, you can do this:
yourDataPasserControllerInstance.previousViewMessageId = posts.postKey
And present the instance!
To pass a value to your Navigation Controller's Root View Controller, you access viewControllers[0] and cast it to the class of your Messages View Controller (the controller that has the previousViewMessageId property):
func () {
let messagesNC = storyboard?.instantiateViewControllerWithIdentifier("messagesViewController") as! UINavigationController
let messagesVC = messagesNC.viewControllers.first as! MessagesViewController
messagesVC.previousViewMessageId = postList[indexPath.row].postKey
presentViewController(messagesNC, animated: true, completion: nil)
}
What you have there is simply presenting a view controller... You are skipping the navigation controller.
What you need to do is present the new view controller inside the navigation controller. Once you have done that, it will show correctly. You can also pass the variables after you've created the vc variable.
This presents the new viewController (vc) within the navigation controller...
self.navigationController?.pushViewController(vc, animated: false)
This sets the variable in the new viewController (vc) (you are correct)
vc.previousViewMessageId = posts.postKey
So complete:
func(){
let vc = storyboard?.instantiateViewControllerWithIdentifier("messagesViewController") as! MessagesViewController
let posts = self.postList[indexPath.row]
//this is the var that i want to past
vc.previousViewMessageId = posts.postKey
navigationController?.pushViewController(vc, animated: false)
}
PS. While not part of the question, I feel I should still mention... Use of the word self should be left to necessity only. In other words, don't use it when it isn't needed. for example self.postList[indexPath.row] :)
https://github.com/raywenderlich/swift-style-guide#use-of-self

Swift - Access different View Controllers in App Delegate

In app delegate, with a simple app having only 2 screens:
first screen is a Table View Controller embedded in Navigation Controller
second screen is a View Controller which is used to add items to the first screen table via protocol/delegate/segue
And this is the code for didFinishLaunchingWithOptions in app delegate that I can reference the first screen as viewController[0]:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let navController = self.window?.rootViewController as! UINavigationController
let courseListController = navController.viewControllers[0] as! CourseListController
courseListController.managedObjectContext = self.managedObjectContext
return true
}
How can I reference the screens at above, below and next to the center sreen? Please suggest me a solution. Thank you!
It's important to keep in mind that the view controller objects for all of the "peripheral" view controllers in your story board won't actually exist until the segue to get to them is executed, so there's no way to get access to them directly from the app delegate. Instead, you need to push state to each child view controller as it's created, from whatever the source view controller is. Segues are the appropriate way to do this.
You will probably want to assign each of the segues from the central view controller a unique segue identifier in Interface Builder. Click on the segue, then enter it here:
In the central view controller, implement prepareForSegue(_:sender:), doing something like the following:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject) {
switch segue.identifier {
case "SegueIdentifier1":
guard let destination = segue.destinationViewController as? ViewController1 else {
return
}
// set up your view controller here
case "SegueIdentifier2":
guard let destination = segue.destinationViewController as? ViewController2 else {
return
}
// set up your view controller here
// add additional segues as required
default:
break // unknown segue
}
}
Go to each view Controller you want to reference and in the identity inspector, add some string to its StoryBoard ID.
next to reference it from the new ViewController (say, XViewController) to (say, YViewController)
do this :
var referencedViewController = self?.storyboard.
instantiateViewControllerWithIdentifier("referenceViewID") as! YViewController
self.presentViewController(referencedViewController,
animated: true, completion: nil)