0
votes

Whats the best way to pass data to a UITabBarController from a UIViewController in Swift 3?

I am building a single view application and I have a details view which needs to be split into 4 sections. I want to use a TabBar to achieve this and pass an ID from a list in UIViewController and then pass that value down to each individual UIViewController in the TabBar. This is so that I can call a web method which takes the ID to fill out data in the individual views.

The app is being converted from Obj-C with a Storyboard to Swift 3 without a Storyboard so I don't have access to the usual segue definitions I did have. I also used to use UserDefaults in the Obj-C version to save away the selected ID and then pull it out again in the individual views. However, I'm not convinced this is the best way to achieve what I am after.

So far I have tried passing along by accessing the UITabBarController class in the initial UIViewController and setting a variable in the ViewController and then passing it down to the ViewController in the first tab. This works if I am pushing from UIViewController to UIViewController (The first view in the TabBar, but run standalone) but doesn't work when the target Controller is a TabBarController.

I have also tried posting a Notification in the ViewControler and Observing the result in the TabBarController. However the observe code is never called. I'm using:

Selected Row:

NotificationCenter.default.post(name: notificationName, object: selectedRowID)

Then in ViewDidLoad on the TabBarController (Also tried viewDidAppear and viewWillAppear):

NotificationCenter.default.addObserver(self, selector: #selector(setID), name: notificationName, object: nil)

The above works, BUT, only when I select the second tab and then go back to the first tab and then it gets called twice!?!?!

I have also tried a Singleton class, but that just flat out didn't work.

Is using UserDefaults really the best way to do this?

2

2 Answers

1
votes

You can create a new class holding the variables to pass the value:

class MyTabController: UITabBarController {
    var myPassedString = String()
}

Go to the StoryBoard, select the tab bar controller and open the Identity inspector, change the class to: MyTabController.

let tabBarController = window?.rootViewController as? UITabBarController

Define in each ViewController where you need the shared data:

var myPassedString = String()

To make to this variable shared, code in each ViewController:

override func viewDidLoad() {
  super.viewDidLoad()  
  myPassedString = (tabBarController as! MyTabController).myPassedString
}
0
votes

Thanks. I am not using a storyboard.

Got it working using a singleton after realising that 1. To get the values back out you must call the singleton in viewWillAppear rather than viewDidLoad and 2. When programmatically creating this, the viewWillAppear of the first child view in the TabBar is observed instead of the viewWillAppear of the actual TabBar controller itself.

for reference for anyone else trying to do similar, my code as follows

open class LastAccessedEvent {
    var ID : String = ""
    class var sharedInstance : LastAccessedEvent {
        struct Static {
            static let instance : LastAccessedEvent = LastAccessedEvent()
    }
        return Static.instance
    }

    var EventID : String {
        get{
            return self.ID
        }

        set {
            self.ID = newValue
        }
    }
}

then in the viewWillAppear of the child view,

    if !LastAccessedEvent.sharedInstance.ID.isEmpty{
        let myEventID = LastAccessedEvent.sharedInstance.ID
    }