Swift iOS -How to pop to different SegmentControl Index using a NavigationController - ios

//Index=0 //contains buttonToSwitchTab to pop to TabOneVC
TabZeroNavCntrlr ----TabZeroVC --- TabChangeVC
//segmntCntrl /
NavCntlr--ContainerView---
\ //Index=1
TabOneNavCntrlr ---- TabOneVC
I have a NavController that hasContainerView connected to it. Inside the containerView there is a segmentControl. The containerView has 2 more nav controllers connected to it that each lead to their own child controllers: TabZeroVC and TabOneVC. Initially the first view shown is TabZeroVC (selectedSegmentIndex = 0). There is a button inside there that leads to TabChangeVC which has a buttonToSwitchTab inside of it. Pressing that button I want to pop to TabOneVC.
I tried this code below by using my navigation controller to make the switch but on the line tabOneVC.segmentedControl.selectedSegmentIndex = 1 I get a crash: unexpectedly found nil while unwrapping an Optional value
I put a break point on it and the containerVC gets initialized but it's 3 properties segmentedControl, tabZeroVC, and tabOneVC are all coming up as nil. Since segmentedControl is nil that's where the crash is happening.
class TabChangeVC: UIViewController{
#IBAction func buttonToSwitchTab(sender: UIButton){
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let containerVC = mainStoryboard.instantiateViewControllerWithIdentifier("ContainerViewController") as! ContainerViewController
containerVC.segmentedControl.selectedSegmentIndex = 1 //crash happens here
self.navigationController?.popToViewController(containerVC, animated: true)
}
}
ContainerView:
class ContainerViewController: UIViewController{
#IBOutlet weak var segmentedControl: UISegmentedControl!
#IBOutlet weak var tabZeroVC: UIView!
#IBOutlet weak var tabOneVC: UIView!
...
}
TabOneVC is selectedSegmentIndex = 1
My question is how do I pop to TabOneVC from the TabChangeVC and more importantly why is the containerVC's segmentedControl coming up as nil?

let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil
let tabOneVC = mainStoryboard.instantiateViewControllerWithIdentifier("TabOneNavigationController") //TabOneNavCntrlr identifire
tabOneVC.segmentedControl.selectedSegmentIndex = 1
appDelegate.window!.rootViewController = tabOneVC

I don't know why the segmentedControl is coming up as nil but I was able to pop to tabOneVC by using NSNotificationCenter. I created a func named tabSwitch() with the segment I wanted to show and then I added a listener inside the viewDidLoad of the ContainerViewController:
class ContainerViewController: UIViewController{
#IBOutlet weak var segmentedControl: UISegmentedControl!
#IBOutlet weak var tabZeroVC: UIView!
#IBOutlet weak var tabOneVC: UIView!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(tabSwitch), name: "tabSwitch", object: nil)
}
func tabSwitch(){
self.segmentedControl.selectedSegmentIndex = 1
self.tabZeroVC.hidden = true
self.tabOneVC.hidden = false
}
}
Inside the TabChangeVC I added a notifier to trigger it and navigationController?.popToRootViewControllerAnimated(true) to get back to the root vc:
class TabChangeVC: UIViewController{
#IBAction func buttonToSwitchTab(sender: UIButton){
NSNotificationCenter.defaultCenter().postNotificationName("tabSwitch", object: nil)
self.navigationController?.popToRootViewControllerAnimated(true)
}
}

Related

Xcode: instantiating a view controller with custom variable

So I want to instantiate a view controller from storyboard and change its static variables.
This is "vc1" - the view controller to be instantiated:
import UIKit
class vc1: UIViewController {
#IBOutlet weak var lbl_title: UILabel!
static var title = "initial value"
override func viewDidLoad() {
super.viewDidLoad()
lbl_title.text = vc1.title
}
}
And this is my root vc.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var btn_go: UIButton!
#IBAction func btn_gogogo(_ sender: Any) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "vc1") as! vc1
vc.title = "bla"
self.present(vc, animated: true, completion: nil)
}
}
Here I'm trying to change the static variable of the view controller that I just instantiated,
with no effect. The variable ( in my case 'title' ) is always stuck to its initial value.
What is the problem here?
Best
Mark
Don't try to override the view controller's title property. Instead, create your own:
class vc1: UIViewController {
#IBOutlet weak var lbl_title: UILabel!
var myTitle = "initial value"
override func viewDidLoad() {
super.viewDidLoad()
lbl_title.text = myTitle
}
}
class ViewController: UIViewController {
#IBOutlet weak var btn_go: UIButton!
#IBAction func btn_gogogo(_ sender: Any) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "vc1") as! vc1
vc.myTitle = "bla"
self.present(vc, animated: true, completion: nil)
}
}

Loading a UIViewController into a Container View programmatically

This is in the latest XCode, 11.3. I've looked through the answers to similar questions, but some of the function names and parameters seem to have changed.
While working through a Udemy course, I'm trying to make a simple log in / sign up interface. In my first view controller I have a vertical stack view containing a label, a segmented control, and a container view. The segmented control can be either "Log In" or "Sign Up". I want to load the appropriate view controller when the segmented control changes.
My LogInViewController has a vertical stack view with a text field for username, another for password, and a Log In button. My SignUpViewController has a vertical stack view with text fields for email address, username, password, and password confirmation followed by a Sign Up button.
My first view controller looks like this:
class ViewController: UIViewController
{
#IBOutlet weak var logInSignUpControl: UISegmentedControl!
#IBOutlet var customContainer: UIView!
var logInVC: LogInViewController?
var signUpVC: SignUpViewController?
var activeVC = 0
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
initializeCustomControllers()
}
func initializeCustomControllers()
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
logInVC = storyboard.instantiateViewController(withIdentifier: "LogInViewController") as? LogInViewController
signUpVC = storyboard.instantiateViewController(withIdentifier: "SignUpViewController") as? SignUpViewController
logInVC?.willMove(toParent: self)
logInVC?.view.frame = customContainer.bounds
customContainer.addSubview(logInVC!.view)
addChild(logInVC!)
logInVC?.didMove(toParent: self)
}
Unfortunately, this only shows the LogInViewController, not the label or segmented control.
I haven't been able to find a clear description of how to do this in the latest version of XCode and Swift, so I've pieced this together from various blog posts and Stackoverflow comments about older versions. Any help is greatly appreciated.
Try the below code :)
PS: #IBAction func controlChanged(_ sender: Any) is an IBAction for the "ValueChanged" Event
class ViewController: UIViewController {
#IBOutlet weak var logInSignUpControl: UISegmentedControl!
#IBOutlet var customContainer: UIView!
var logInVC: LogInViewController?
var signUpVC: SignUpViewController?
var activeVC = 0
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
initializeCustomControllers()
}
#IBAction func controlChanged(_ sender: Any) {
changeVC()
}
func changeVC() {
if activeVC == 0 {
signUpVC?.view.removeFromSuperview()
logInVC?.willMove(toParent: self)
logInVC?.view.frame = customContainer.bounds
customContainer.addSubview(logInVC!.view)
addChild(logInVC!)
logInVC?.didMove(toParent: self)
} else {
logInVC?.view.removeFromSuperview()
signUpVC?.willMove(toParent: self)
signUpVC?.view.frame = customContainer.bounds
customContainer.addSubview(signUpVC!.view)
addChild(signUpVC!)
signUpVC?.didMove(toParent: self)
}
activeVC = activeVC == 0 ? 1 : 0
}
func initializeCustomControllers()
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
logInVC = storyboard.instantiateViewController(withIdentifier: "LogInViewController") as? LogInViewController
signUpVC = storyboard.instantiateViewController(withIdentifier: "SignUpViewController") as? SignUpViewController
changeVC()
}
}
Make sure this #IBOutlet var customContainer: UIView! is linked to the containerview and not to the vc's main view in storyboard

how can I manage controllers in Container View with using tab bar

On my storyboard I have main ViewController, not TabBarViewController, which consist of TabBar on the bottom, view on the top and ContainerView on the middle. ContainerView have a NavigationController. I also have 4 ViewControllers, one of them - RootViewController of NavigationController. I wish to show one of ViewControllers when I selecting TabBarItem, and in future I will add slide menu, which also will show selected ViewController.
I have next code, which only shows initial ViewController inside ContainerView, and when I selecting TabBarItems, new ViewControllers don't showing and I see only first View Controller. What goes wrong?
class ViewController: UIViewController {
#IBOutlet weak var container: UIView!
#IBOutlet weak var first: UITabBarItem!
#IBOutlet weak var second: UITabBarItem!
#IBOutlet weak var third: UITabBarItem!
#IBOutlet weak var fours: UITabBarItem!
#IBOutlet weak var tabBar: UITabBar!
var firstVC: FirstViewController?
var secondVC: SecondViewController?
var thirdVC: ThirdViewController?
var foursVC: FoursViewController?
var navi: UINavigationController?
override func viewDidLoad() {
super.viewDidLoad()
tabBar.delegate = self
initialSetup()
}
func initialSetup() {
tabBar.selectedItem = tabBar.items?.first
navi = self.storyboard?.instantiateViewController(withIdentifier: "containerNavi") as? UINavigationController
firstVC = self.storyboard?.instantiateViewController(withIdentifier: "FirstViewController") as? FirstViewController
secondVC = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController
thirdVC = self.storyboard?.instantiateViewController(withIdentifier: "ThirdViewController") as? ThirdViewController
foursVC = self.storyboard?.instantiateViewController(withIdentifier: "FoursViewController") as? FoursViewController
}
func showVC(number: Int) {
switch number {
case 0:
navi?.popToRootViewController(animated: true)
print("0")
case 1:
if let second = secondVC {
navi?.pushViewController(second, animated: true)
}
print("1")
case 2:
if let third = thirdVC {
navi?.pushViewController(third, animated: true)
}
print("2")
case 3:
if let fours = foursVC {
navi?.pushViewController(fours, animated: true)
}
print("3")
default:
return
}
}
}
extension ViewController: UITabBarDelegate {
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
showVC(number: item.tag)
}
}
Storyboard screenshot:
You can try to use this extesion to add/remove any of the 4 to containerView
extension UIViewController {
func add(_ child: UIViewController, frame: CGRect? = nil) {
addChildViewController(child)
if let frame = frame {
child.view.frame = frame
}
view.addSubview(child.view)
child.didMove(toParentViewController: self)
}
func remove() {
willMove(toParentViewController: nil)
view.removeFromSuperview()
removeFromParentViewController()
}
}
// use it like this
let vc = self.storyboard?.instantiateViewController(withIdentifier: "first")
self.add(vc, frame: self.containerView.frame)
to remove
vc.remove()

Swift: How to pass information to a pop up view?

I am trying to pass information to my custom PopUpViewController using the github extension (https://github.com/Orderella/PopupDialog). The Popup uses a viewcontroller I've named PopUpViewController(with a xib file), and the view controller that the PopUp is initiated from is called MainViewController.
The information passed to the PopUpViewController will be an array(named: popUpArray) of type String and used for displaying the contained information within a table (named: tableView).
MainViewController code:
func showCustomDialog(_ sender: UIButton) {
// Create a custom view controller
let PopUpVC = PopUpViewController(nibName: "PopUpViewController", bundle: nil)
// Create the dialog
let popup = PopupDialog(viewController: PopUpVC, buttonAlignment: .horizontal, transitionStyle: .bounceDown, gestureDismissal: true)
// Create second button
let buttonOne = DefaultButton(title: "Ok", dismissOnTap: true) {
}
// Add buttons to dialog
popup.addButton(buttonOne)
// Present dialog
present(popup, animated: true, completion: nil)
}
PopUpViewController Code:
import UIKit
class PopUpViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var tableView: UITableView!
Just declare a new variable on PopUpViewController called data with type Array<String>.
After this, when you are creating your viewController, you can just pass it to the controller. After that it is just a simple tableView implementation in PopUpViewController to display the data.
Extend PopUpViewController with data parameter.
import UIKit
class PopUpViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var tableView: UITableView!
// Data variable
public var data: [String] = []
}
Add the data upon calling showCustomDialog() function
// Create a custom view controller
let PopUpVC = PopUpViewController(nibName: "PopUpViewController", bundle: nil)
// Assign the data
PopUpVC.data = popUpArray
Create a convenience init in PopUpViewController like following
convenience init(nibName: String, arrayOfString: [String] ){
self.data = arrayOfString
self.init(nibName: nibName, bundle:nil)
}
Then on MainViewController call the convenience init you just created like this something like this
// Create a custom view controller
let PopUpVC = PopUpViewController("PopUpViewController", arrayOfString: ["String1", "String2"])

"fatal error: unexpectedly found nil while unwrapping an Optional value" while assigning viewcontrollers to tabbar

I have written some code which works fine in simulator but its not working in Device. I have assigned 4 viewcontrollers to tabbar and the following is the code for HomeScreen, which is assigned as a first view controller in tabbar. It crashes on the first line of viewdidload().
when I remove everything from viewdidload() it works.
class HomeScreen: UIViewController {
var tableView: UITableView!
#IBOutlet weak var imgLine:UIImageView!
#IBOutlet weak var btnActiveDeals:UIButton!
#IBOutlet weak var btnActiveClaims:UIButton!
#IBOutlet weak var btnNearByDeals:UIButton!
#IBOutlet weak var horizontalSpaceConstraint:NSLayoutConstraint!
#IBOutlet weak var tblMain:UITableView!
var mydeals : MyDealsViewController!
override func viewDidLoad() {
super.viewDidLoad()
btnActiveDeals.titleLabel?.adjustsFontSizeToFitWidth = true
btnActiveDeals.titleLabel?.minimumScaleFactor = 0.5
btnActiveDeals.autoresizesSubviews = true
btnActiveClaims.titleLabel?.adjustsFontSizeToFitWidth = true
btnActiveClaims.titleLabel?.minimumScaleFactor = 0.5
btnActiveClaims.autoresizesSubviews = true
btnNearByDeals.titleLabel?.adjustsFontSizeToFitWidth = true
btnNearByDeals.titleLabel?.minimumScaleFactor = 0.5
btnNearByDeals.autoresizesSubviews = true
tblMain.backgroundView = nil
tblMain.backgroundColor = UIColor.clearColor()
}
Please find below code for assigning the homescreen to tabbar.
let centerViewController1 = HomeScreen(nibName: "HomeScreen", bundle: nil)
let centerViewController2 = HomeScreen(nibName: "HomeScreen", bundle: nil)
let centerViewController3 = HomeScreen(nibName: "HomeScreen", bundle: nil)
let centerViewController4 = HomeScreen(nibName: "HomeScreen", bundle: nil)
tabBarController = UITabBarController()
var controllers = [centerViewController1,centerViewController2,centerViewController3,centerViewController4]
tabBarController.viewControllers = controllers
tabBarController.tabBar.tintColor = UIColor.whiteColor()
Please guide me. Thanks in advance.
It is failing because at viewDidLoad, btnActiveDeals is not yet initiated.
Reason: The way you are initialising your view controller.
Solution:
1- If you have created your viewcontroller in storyboard please instantiate it like below
if let vc = storyboard?.instantiateViewController(withIdentifier: "IdentifierDefinedInStoryboard") as? VC {
self.navigationController?.pushViewController(vc, animated: true)
}
2- If you have created your viewcontroller in xib, please instantiate it like below
let centerViewController1 = CenterViewController()
please tell me if it helps!

Resources