UITabBarController viewDidLoad not running - swift

I have a custom class like below connected to Tab View Controller on storyboard but the problem is the class' viewDidLoad and the didSelected is never called, yet the when i run the app the tab is visible and working fine
import UIKit
import Locksmith
class TabViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
print("ANY")
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
extension TabViewController: UITabBarControllerDelegate{
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print(item.tag)
if item == (self.tabBar.items as! [UITabBarItem])[2]{
let user_id_dict = Locksmith.loadDataForUserAccount(userAccount: "USER_ID")
let user_id = user_id_dict?["userId"]
print("HELLLPP", user_id)
}
}
}
And in IB its already connected but not running
Any help please as to why the viewDidLoas and didSelect is never called

Related

Button title set only for the second tab

In my project there is a Segue Show(e.g. Push). After clicking the mainButton, TabBarController is presented. When I choose the second tab, the method setButtonsTitle is called and when I swipe the TabBarController down, I can see "item 2" instead of the "Button" title (default title). But when I click the first tab afterwards and swipe the TabBarController down, it remains "Button". My first thought was that the method does not get called, but this is not true (checked in debugger). Also, print(title) shows "Item 1".
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var mainButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destination = segue.destination as! TabBarController
destination.selectionDelegate = self
}
}
extension ViewController : ButtonThings {
func setButtonsTitle(title: String){
mainButton.titleLabel?.text = title
print(title)
}
}
And the TabBarController:
import UIKit
class TabBarController: UITabBarController {
weak var selectionDelegate: ButtonThings?
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: UITabBarController
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
selectionDelegate?.setButtonsTitle(title: item.title ?? "no title")
}
}
protocol ButtonThings : class {
func setButtonsTitle(title: String)
}
I was able to reproduce that issue that you had mentioned. I then set the button type to custom and the button title started showing correctly.
Hope this helps.

Passing Data between view Controllers Using a segue from a view embedded in a navigation controller to a tabbarcontroller

I have two views that I would like to pass data from one view to the next. The first view is where I have the data that I would like to pass to the next view lets call it SourceViewController. However SourceViewController is embedded in a NavigationViewController and the secondViewController lets call it DestinationViewController is the firstView in a TabViewController.
I have tried to use the answer from this question and it fails to go past navigation view it just skips the whole logic.
This is my code :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "loginSuccessSugue") {
if let tab = self.presentingViewController as? UITabBarController,
let nav = tab.viewControllers?[0] as? UINavigationController,
let destinationVC = nav.viewControllers.first as? HomeViewController {
destinationVC.currentBalance = serviceBalance
}
}
}
This is the HomeViewController:
class HomeViewController: UIViewController , UITableViewDelegate,UITableViewDataSource, UICircularProgressRingDelegate{
var currentBalance = 0.0
override func viewDidLoad() {
super.viewDidLoad()
circularBalance.maxValue = CGFloat(currentBalance)
print(currentBalance)
}
override func viewDidAppear(_ animated: Bool) {
print(currentBalance)
circularBalance.setProgress(value: CGFloat(currentBalance), animationDuration: 3)
}
}
This is how the storyboard looks like:
This is my view controller where you can check that I am sending 5 to tabbar first viewcontroller:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.performSegue(withIdentifier: "segueIdentifier", sender: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let barViewControllers = segue.destination as! UITabBarController
let destinationNv = barViewControllers.viewControllers?[0] as! UINavigationController
let destinationViewController = destinationNv.viewControllers[0] as! FirstViewController
destinationViewController.currentBalance = 5
}
}
Now You can check my firstview controller where you can check that what value we are getting.
class FirstViewController: UIViewController {
var currentBalance = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print(currentBalance)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Now, You can check my console and storyboard:
From Apple's UIViewController docs:
var presentingViewController: UIViewController?
The view controller that presented this view controller.
Which would work great for you, ** IF ** you were trying to go back in your navigational hierarchy, as did the guy in the SO post you referenced.
You are trying cast the VC THAT PRESENTED SOURCEVIEWCONTROLLER of your SourceViewController as a UITabBarController, which fails miserably, and is why you never hit a breakpoint inside your nested if let's.
If we look the next variable down from this in the docs we can see something that will take us forward to the UIViewController we are presenting:
var presentedViewController: UIViewController?
The view controller that is presented by this view controller, or one
of its ancestors in the view controller hierarchy.
So now to go over the code you need to solve your predicament. I'll give you the same code you posted, but fixing the tense of my verbs in the comments:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "loginSuccessSugue") {
//ing -> ed
if let tab = self.presentingViewController as? UITabBarController,
let nav = tab.viewControllers?[0] as? UINavigationController,
let destinationVC = nav.viewControllers.first as? HomeViewController {
destinationVC.currentBalance = serviceBalance
}
}
Isn't it frustrating when the English language tricks you up more than swift?
EDIT:
Since you are passing the data in prepareForSegue: you will actually want to get the UITabBarController from segue.destination. And since the the UITabBarController's ViewControllers property will be nil or empty in prepare for segue. This is a bad approach for passing the data.
You may need to create custom subclass of UITabBarController, pass it the variable, and then pass that data to its viewControllers in viewDidLoad.
class MyTabBarController: UITabBarController {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
var serviceBalance : Double?
override func viewDidLoad() {
super.viewDidLoad()
//Make sure vc is not null or empty before continuing.
guard let vcs = viewControllers, !vcs.isEmpty else {
return
}
if let navVC = vcs[0] as? UINavigationController, let destinationVC = navVC.viewControllers[0] as? UIViewController {
destinationVC.serviceBalance = destinationVC
}
}
}
Updated prepareForSegue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let tabBarVC = segue.destination as? MyTabBarController {
tabBarVC.serviceBalance = serviceBalance
}
}
Don't forget to change the UITabBarController's class in the identity inspector of storyboard to MyTabBarController
You need to change if() condition code.
Use below code will get your HomeViewController in destination of segue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "loginSuccessSugue") {
if let destinationVC = segue.destination as? HomeViewController {
destinationVC.currentBalance = serviceBalance
}
}
}
As in segue.destination you will get your HomeViewController so no need to get it from Tab + Navigation stack.
Edit:
let destinationVC = segue.destination as? HomeViewController
Print(destinationVC)
Hope this solution will helps!

Delegate using Container View in Swift

I'm developing an app for iPad Pro. In this app, containerView use to add additional views and interact with them.
First, I created a protocol:
protocol DataViewDelegate {
func setTouch(touch: Bool)
}
Then, I created my first view controller
import UIKit
class ViewController: UIViewController, DataViewDelegate {
#IBOutlet var container: UIView!
#IBOutlet var labelText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func setTouch(touch: Bool) {
if touch == true {
labelText.text = "Touch!"
}
}
}
And finally, I created a view that will be embedded in containerView.
import UIKit
class ContainerViewController: UIViewController {
var dataViewDelegate: DataViewDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func touchMe(sender: AnyObject) {
dataViewDelegate?. setTouch(true)
}
}
But for some reason, nothing happened, the first view controller receives nothing in setTouch function.
My question is: In this case, using container, how can I make the communication between two ViewsControllers?
Like #nwales said you haven't yet set the delegate. You should do set the delegate in prepareForSegue function on your first viewController (who contain the viewContainer)
First select the embed segue and set an identifier in the attributes inspector.
Then in the parentViewController implement the func prepareForSegue like this:
Swift 4+:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "the identifier") {
let embedVC = segue.destination as! ViewController
embedVC.delegate = self
}
}
Below:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if (segue.identifier == "the identifier") {
let embedVC = segue.destinationViewController as! ContainerViewController
embedVC.dataViewDelegate = self
}
}
Looks like you defined the delegate, but have not set the delegate. This happens to me all the time.

Popovers in Storyboard, how to handle the delegate

In a storyboard i have a view controller which has a segue to another viewcontroller, with the "Present As Popover" applied. If i don't add any code, this works as id expect.
Issue:
I need to get the delegate working so i can get data back from the popover. I have created the delegate in the popover.
I have added
class LoginView: UIViewController,UIPopoverPresentationControllerDelegate, UIPopoverControllerDelegate,KeypadDelegate
I have added the functions to my main view controller.
Issue i have is how to set the delegate on the segue.
i have tried
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "KeyPadLoad"
{
let popoverViewController = segue.destinationViewController as! UIViewController
popoverViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
popoverViewController.popoverPresentationController!.delegate = self
}
}
The segue is defiantly called KeyPadLoad but when the delegate functions should be called in the popover nothing happens.
What am i doing wrong
Thanks
You have to implement the UIPopoverPresentationControllerDelegate in the class that presents the Popover. The methods of the UIPopoverPresentationControllerDelegate protocol let you customize the behavior of a popover-based presentation.
If you have set a segue to go to the Popover and you set the segue as Present as Popover then your class has to be like this :
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var popOver = segue.destinationViewController as! PopOverViewController
popOver.popoverPresentationController!.delegate = self
}
// Tells the delegate that the popover was dismissed.
func popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) {
println("dismissed")
}
}
Where the class PopOverViewController is just an UIViewController that handle the Popover, no more, something like this code :
class PopOverViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
With the above code you should see the message:
dismissed
Every time that the PopOverViewController is dismissed.
I hope this help you.

How to access the same view from another view by multiple buttons

I am creating a game in swift and my goal is have each game level access the same view controller, but I need to send unique information from the button reaching that view controller so that I can access core data in the next view controller based on the information sent from the first view controller.
My problem is I do not know how to send multiple pieces of information from the first view controller to the second view controller in the prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
I tried setting the unique information of each button in the keyPath storage, but I can't access it
LevelsMainScreen.swift
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var dest : Levels = segue.destinationViewController as Levels
//Getting the value of the keyPath of the tapped button to send to levels view controller
dest.level = sender?.keyPath("levels")
}
Here is the view controller I want to send it to so I can start to access core data information
class Levels: UIViewController {
#IBOutlet var lblSubLevel: UILabel!
#IBOutlet var lblLevel: UILabel!
var level = Int()
var subLevel = Int()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
lblLevel.text = "\(level.value)"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
`
You have to set an identifier for each segue from the storyboard in attributes inspector. Then, in the LevelsMainScreen.swift controller prepareForSeque method check for the segue identifier is equal to the repective segue identifier given by you. There you can assign the levels as you wanted.
ie., Name the the segue identifier as segue1, segue2, segue3 from attribute inspector in each segue.
In the LevelsMainScreen,
override func prepareForSegue(segue: UIStoryboardSegue, sender:AnyObject?) {
var dest : Levels = segue.destinationViewController as Levels
if(segue.identifier == "segue1") {
//set your customized level values here...
//ie., dest.level = 1
}
else if(segue.identifier == "segue2") {
//set your customized level values here...
}
else if(segue.identifier == "segue3") {
//set your customized level values here...
}
}