swift; xcode 9.2 - Passing arguments over TabBar & navigation controller - ios

In my storyboard I got:
UIView -> UITabBarController -> UINavigationController -> UITableView
Now I want to pass an object from UIView into UITableview. I do get the object to the TabBarController from the prepare for segue func, but from there I kind of get lost.
How to identify what segue you have on the itemlist from the TabBarController?
Could somebody give some example code for the UITabBar and Navigation controller to pass the data?

Phillip is right.
You can do it as following:
class Model {
static let shared = Model()
var data: String // or anything else
}
in UIView:
Model.shared.data = "some data"
in UITableView
let data = Model.shared.data
//do smth with data...

Anton is suggesting the Singleton pattern. It is important to understand what it is when you decide to use it has both its benefits and potential pitfalls. https://thatthinginswift.com/singletons/ is a place to start reading up.
There are ways to just pass an object from one view to the other and that is useful knowledge to know. Both TabBarVC's and NavigationVC's have their viewControllers property which allows you to access an array of their child vc's. You can use this to pass information to specific child vc's. Depending on your needs this may be more appropriate than creating a singleton.
For example:
let childVC = tabBarVC.viewControllers[0] as! MyCustomVCClass
childVC.inheretedObject = objectIWantToSend
This would pass an object to the vc that ocupies the first tab of a tab bar vc.

Related

How to pass data between views. When should I use what?

I have a View-Hierarchy like this:
UIViewController (SingleEventViewController)
UIScrollView (EventScrollView)
UIView (contentView)
3xUITableView (SurePeopleTV, MaybePeopleTV, NopePeopleTV (all inherited from the same UITableView)), & all other UI-Elements
The SingleEventViewController stores one Event (passed within the initializer). (All Events are stored in Core-Data).
The three UITableViews are there for displaying the users which are participating (or not or maybe) at the Event. My question is, what are the possibilities to fill the tableViews with the data and what would you recommend in which situation.
Currently I have a property parentVC: SingleEventViewController in all Subviews and get the data like this:
override func loadUsers() {
//class SurePeopleTV
guard let parentController = parentVC else { return }
users = (parentController.thisEvent.eventSureParticipants?.allObjects as! [User])
finishedLoading = true
super.loadUsers()
}
.
func applyDefaultValues() {
//class EventScrollView
guard let parent = parentVC else { return }
titleLabel.text = parent.eventName
}
I'm new to programming but I got a feeling that I should not create a parentVC reference in all of my classes.
An object should not (ideally) know about its parent - if it does they are "tightly coupled". If you change the object's parent, your code may break. In your case, your parent object must have a thisEvent property.
You want your objects to be "loosely coupled", so the object doesn't know about a specific parent object.
In Swift, the usual ways to pass information "back up the chain" is to use the delegate design pattern… https://developer.apple.com/documentation/swift/cocoa_design_patterns or to use closures.
See also https://www.andrewcbancroft.com/2015/04/08/how-delegation-works-a-swift-developer-guide/ for info on delegation
First of all, if you create a reference to the parent ViewController make sure it is weak, otherwise you can run into memory management issues.
Edit: As Ashley Mills said, delegates the way to handle this
The recommended way to pass data between ViewControllers is using something like this
Every time a segue is performed from the view controller this function is in this function is called. This code first checks what identifier the segue has, and if it is the one that you want, you can access a reference to the next view controller and pass data to it.

How to pass data between Swift files without prepareForSegue?

I currently have three Swift files, one for the main view in a ViewController, and two more which are used for the two views within the first view, which are used for a Segmented Control.
As these don't use segues between each other, I can't use the prepareForSegue method to transfer data between them, so how do transfer the variables and such from one file to another?
This doesn't seem to be a duplicate as other cases such as the one commented are using segues, mine is not.
Are all three Swift classes view controller subclasses?
You have your main view controller with your segmented control. For each segmented, I would create a new view controller subclass.
On your main view controller, for each segment, use a 'Container View' instead of a UIView object.
This will create two new 'screens' in the storyboard, attached to your main view controller with a segue. These new screens will be UIViewControllers, you can change them to be your subclass's as normal.
You can now use your prepareForSegue function as normal to set data in your segmented control view controllers.
So you have something like viewControllerMain, which contains viewSegmentedOne and viewSegmentedTwo, and you want to be able to access `viewControllerMain.myProperty' ?
You can always navigate through the hierarchy to get parent views - but the easiest option could be to include a reference to viewControllerMain in each of the segmented controls
var myParentVC : ViewControllerMain?
then when you create the subviews
mySubView.myParentVC = self
If you are using storyboard for view controllers, then try like this:
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Your_VC_Identifier");
viewController.Your_var = Your_value_to_assign
NOTE: Define Your_var in your ViewController class
You just need to create an instance of the view controller you want to display, this is easy such as calling on the storyboard instance (usually the presenting view controller has one) instantiateViewController(withIdentifier:), by using an identifier that you provide in the storyboard file.
One created you can pass the data you want by casting it to your view controller class and present it as you prefer.
One method would be using singleton class . https://cocoacasts.com/what-is-a-singleton-and-how-to-create-one-in-swift/ this is how you can make singleton class.
other method could be using nsuserdefaults.
You need to decide which approach is best according to your requirement.
try this:
let defaults = UserDefaults.standard()
defaults.set(yourdata, forKey: "someObject")
print(defaults.object(forKey: "someObject"))
You can try use Extensions for UIViewController
private var storedDataKey: UInt8 = 0
extension UIViewController {
var storedViewControllerData: UIViewController? {
get {
return objc_getAssociatedObject(self, &storedDataKey) as? UIViewController
}
set(newValue) {
objc_setAssociatedObject(self, &storedDataKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN)
}
}
}
This very useful you can send data with chain like:
viewControllerB.storedViewControllerData = viewControllerA.storedViewControllerData
or
func viewDidLoad() {
doSomething(self.storedViewControllerData)
}

iOS - How to use a small view in different view controllers in Swift

I have a progress bar (with its own controller). This bar is supposed to be shown in different views depending on which view is visible. As the progress will be same, If possible I don't want to create many progress bar in many views rather I want to use same instance in all these views. Also in that way when I need to change any property of the progress bar it will be reflected commonly, which is required.
Please suggest me how can I use this common view. And also if my strategy is wrong, what would be the better design for such scenarios.
1) Well you have 2 options. You can declare a new Class ViewBox (or whatever name) and then use that inside your code
First View Controller
var box:ViewBox = ViewBox()
When you segue or transition to your next screen, you can have a predefined variable var box:ViewBox!. Then say when you press a button, the button has a function called transition.
//Now setup the transition inside the Storyboard and name the identifier "toThirdViewController"
override func prepareForSegue(segue:UIStoryboardSegue, sender:AnyObject?) {
if(segue.identifier == "toThirdViewController") {
var vc = segue.destinationViewController as! `nextViewController` //The class of your next viewcontroller goes here
vc.box = self.box
}
//Since The SecondViewController doesn't need ViewBox, we don't need it there.
}
where
nextViewController:UIViewController {
var box:ViewBox!
}
Or you could do a much simpler way and that is to look up a UIPageViewController :)

How to pass data from one tabbar to another in swift?

I want to pass data from one tabBar controller to another,
I am switching tabBar using tabBarController?.selectedIndex = 0
I tried many option but unable to pass data to another tab, is there any simple solution like we pass data using navigation controller?
Tabs are usually some custom UIViewControllers. From these view controllers (tabs) you can also get access to the UITabBarController with something like:
if let mainController = UIApplication.sharedApplication().delegate?.window??.rootViewController as? YourMainTabBarControllerClass {
mainController.someVariable = 123
}
Here you have to be careful, because the tab bar controller may not be the rootViewController, see this question for more details.
In order to store some properties in the UITabBarController you have to implement your own class by extending UITabBarController and then set the custom class in the StoryBoard. The class will then look like:
class YourMainTabBarControllerClass: UITabBarController {
// some custom variables here...
var someVariable = 0
...
}

Programmatically Passing Variables Through View Controllers in Swift Without StoryBoards

I am creating an iOS application and my question should be simple.
If in View Controller 1 I have a simple string variable called "name" how do I then pass the value of "name" to View Controller 2.
I realize this question has been asked many times before, however all the answers I can find have had responses pertaining to storyboards and segues. I am not using Story Boards so I am wondering if there is a way to do this without them.
Many Thanks
You do this the same way in Swift as you do in Objective-C.
Write VC2 with a property to hold the value you want to pass it.
Create an instance of VC2 from VC1
Set the property on VC2 with the value from VC1.
Display the view of VC2.
So simply you have to do something like:
class ViewController: UIViewController {
var secondVC: VC2!
override func viewDidLoad() {
secondVC = VC()
secondVC.someProperty = "Some Value"
}
}
So your VC2 should have such property as someProperty

Resources