I have UIViewController and how I can to convert UIViewController to Class.swift. Class is initialized...
MainController.staticInstance.viewControllers?[1] as! Destination
MainController is class which extending UITabBarController. I want to get child controller from UITabBar and convert it to Class which parent.
Clearly example:
class MainController: UITabBarController {
override func viewDidLoad() {
(self.viewControllers?[1] as! Destination).itsMyFunction();
}
}
MAXIMUM DETAIL:
1 class
class First: UIViewController {
func itsMyFunction() {
print("Hello world!")
}
}
this is Class I attach to class in STORYBOARD!
2 class
class MainController: UITabBarController {
func override viewDidLoad() {
// Here I set index UITabBar ITEM which attach to MAIN UiTabBarController
self.selectedIndex = 0
// NOW I want to get INSTANCE CLASS First
(self.viewControllers?[1] as! First).itsMyFunction();
}
}
Can you please follow this setup example?
class TabBarViewController: UITabBarController {
let firstVC = First()
let secondVC = SecondViewController()
override func viewDidLoad() {
super.viewDidLoad()
firstVC.tabBarItem = UITabBarItem(tabBarSystemItem: .search, tag: 0)
secondVC.tabBarItem = UITabBarItem(tabBarSystemItem: .more, tag: 1)
let tabBarList = [firstVC, secondVC]
viewControllers = tabBarList
if let destination = viewControllers?.first as? First {
destination.itsMyFunction()
}
}
}
It seems that you fail to get the Class instance of the controller because your viewControllers array is empty based on the code that you posted. Let me know if it worked.
That way you get a crash if the type is something different. Try to avoid using ! whenever you can.
Use a weak cast and evaluate the unwrapped type if its yours.
if let destination = destMainController.staticInstance.viewControllers?.first as? Destination {
destination.itsMyFunction()
}
Related
About
I'm developping ios app with MXParallaxHeader.
I use it in order to create twitter-like UI.
However, I don't know how to pass data from MXScrollView to childViewController when I go MXScrollView page.
Question
How could I pass data from MXScrollView to childViewController?
Sample Code
PreviousViewController
//MXScrollViewController=ParentVC of MarkerInfoTabViewController
class PreviousViewController:UIViewController {
.
.
#IBAction func goMXScrollView(_ sender: Any) {
let nextView = self.storyboard?.instantiateViewController(withIdentifier: "MXScrollViewController") as! MXScrollViewController
self.navigationController?.pushViewController(nextView, animated: true)
}
}
childViewController
//MarkerInfoTabViewController(=childVC of MXScrollView)
import Tabman
import UIKit
import MXParallaxHeader
class MarkerInfoTabViewController: TabmanViewController {
var marker:Marker!
private var viewControllers = [UIViewController?]()
override func viewDidLoad() {
super.viewDidLoad()
let leftView = self.storyboard?.instantiateViewController(withIdentifier: "MarkerInfoLeftViewController") as! MarkerInfoLeftViewController
let rightView = self.storyboard?.instantiateViewController(withIdentifier: "MarkerInfoRightViewController") as! MarkerInfoRightViewController
//↓I want to pass data here
leftView.marker = marker
viewControllers = [leftView, rightView]
self.dataSource = self
// Create bar
let bar = TMBar.ButtonBar()
bar.layout.transitionStyle = .snap // Customize
// Add to view
addBar(bar, dataSource: self, at: .top)
}
}
My App Image
・storyboard
・segue to header
・segue to childVC
Reference
My app is mostly the same as this app.
Just define a property in the child controller class
class ChildViewController {
var passedData: MY_DATA_TYPE
...
and set it after the instantiation
let nextView = self.storyboard?.instantiateViewController(withIdentifier: "ChildViewController") as! ChildViewController
nextView.passedData = MY_PASSED_DATA
self.navigationController?.pushViewController(nextView, animated: true)
I try to use delegate to reset my ViewControllerA (HomePage) property "type" value when I logout.
But I set breakpoint and my delegate function work success.
When I login again, and print my property "type" in ViewWillAppear. It's also cache old value before I logout.
Please tell me what's wrong with me.
Thanks.
class ViewControllerA: UIViewController, CustomDelegate {
enum Type: Int {
case book = 0
case pen
}
var tmpType: Type?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
printBBLog("tmpType: \(tmpType)") //before I logout the value is "pen",and I login again the value is "pen".
}
func clearType() {
printBBLog("clear")
self.tmpType = nil
printBBLog("\(self.tmpType)")
}
#objc func bookBtnClicked(sender: UIButton) {
self.tmpType = .book
}
#objc func penBtnClicked(sender: UIButton) {
self.tmpType = .pen
}
}
class ViewControllerB: UIViewController {
var delegate: CustomDelegate?
func doLogout() {
let vc = ViewControllerA()
self.delegate = vc
self.delegate?.clearType()
}
}
You are creating a new instance of your ViewControllerA. since you are using the UITabBarController you can access you ViewControllerA from your ViewControllerB and assign the delegate. after that you will get your desired result. for reference please check below code.
class ViewControllerB: UIViewController {
var delegate: CustomDelegate?
func doLogout() {
let viewControllers = self.tabBarController?.viewControllers
if let vc1 = viewControllers[0] as? ViewControllerA {
self.delegate = vc1
self.delegate?.clearType()
}
}
}
if you are using UINavigationController inside the UITabBarcontroller then use:
if let vc1 = ((self.tabBarController?.viewControllers?[0] as? UINavigationController)?.viewControllers[0] as? ViewControllerA)
I'm trying to go from a ViewController1 to a ViewController2 by changing the selectedIndex of the tabBarController.
In ViewController1:
func action() {
_ = self.tabBarController?.selectedIndex = 4
}
In ViewController2:
class ViewController2: UIViewController {
var isOnInfo = true
}
My problem is pretty simple. I would like to change the value of isOnInfo in the action() function.
Is it possible?
Another way to do that would be to create a global var, but if I can avoid that it would be better.
Thank you for you answers.
I can recommend you to move your changing tabs logic in Tab bar controller.
Make your own class TabBarController(subclass of UITabBarController), set it as custom class of your tab bar controller at the storyBoard and move the function action() there.
import UIKit
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
}
func action(isOnInfo: Bool) {
selectedIndex = 4
if let viewControllers = self.viewControllers,
let viewController2 = viewControllers[selectedIndex] as? ViewController2 {
viewController2.isOnInfo = isOnInfo
}
}
}
Then in viewController1:
if let tabBarController = self.tabBarController as? TabBarController {
tabBarController.action(isOnInfo: false)
}
You can get object of viewcontroller at selected index in tabbarcontroller. once you have it, you can modify any public property.
func action() {
_ = self.tabBarController?.selectedIndex = 4
if let vc2 = self.tabBarController?.viewControllers![4] as?
ViewController2
{
vc2.isOnInfo = true
}
}
I have two UIViewControllers, A and B, I connect them within a UIPageViewController:
Here is how it looks in the Storyboard:
I don't know how to pass data to B from A.
Well assume you have some class (which you should have provided) like:
class MyModel {
var dataFromFirstController: Any?
var dataFromSecondController: Any?
var sharedData: Any?
}
Now you need a subclass of page view controller which is the one that controls the data so override view did load to create a model:
var myModel: MyModel!
override func viewDidLoad() {
super.viewDidLoad()
self.myModel = MyModel()
}
Now when you generate or fetch view controllers you simply assign the same model to them:
func getFirstViewController() -> UIViewController {
let controller = MyFirstController.generate()
controller.myModel = self.myModel
return controller
}
func getSecondViewController() -> UIViewController {
let controller = MySecondController.generate()
controller.myModel = self.myModel
return controller
}
Now all 3 view controllers share the same model. This is probably the easiest way of doing it but there are very many ways. The cleanest is probably using delegates which would report back to page controller that would then report back to given view controllers.
I had some difficulty finding a solution to this and came up with something myself using delegation. Suggestions are welcome
In the ViewController sending the data, define a delegate as follows:
protocol FirstVCDelegate {
func foo(someData: String)
}
class FirstViewController: UIViewController {
var delegate: FirstVCDelegate?
....
func someMethod() {
delegate?.foo("first VC")
}
}
In the PageViewController set up your View Controllers as follows:
class PageViewController: UIPageViewController, ... {
var myViewControllers = [UIViewController]()
override func viewDidLoad() {
let firstVC = storyboard?.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
firstVC.delegate = secondVC
myViewControllers.append(firstVC)
myViewControllers.append(secondVC)
}
// MARK: - PageVC Delegate / Datasource
....
and finally, the receiving ViewController implements the delegate as follows:
class SecondViewController: UIViewController, FirstVCDelegate {
....
func foo(data: String) { // This method is triggered from FirstViewController's delegate?.foo("first VC")
print(data) // "first VC" will be printed
}
}
Good luck,
Aaron
I have created tab bar controller programatically which has an array of viewcontroller having instance of RedViewController
class TabBarViewController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
self.delegate = self
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
let tab1 = Red()
let tab1BarItem = UITabBarItem(title: "Tab1", image:UIImage(named:"bell-off-7.png"), selectedImage:UIImage(named:"bell-7.png") )
tab1BarItem.tag = 0
tab1.tabBarItem = tab1BarItem
let tab2 = ObserverViewController()
let tab2BarItem = UITabBarItem(title: "Tab2", image: UIImage(named:"bell-off-7.png"), selectedImage: UIImage(named:"bell-7.png"))
tab2BarItem.tag = 1
tab2.tabBarItem = tab2BarItem
self.viewControllers = [tab1,tab2]
}
}
How can i use the instance of class Red to access a property of it as Array viewController is of UIViewController return type
You just have to cast the UIViewController to Red after retrieving it from the array.
guard let redController = self.viewController.first as? Red else {return}
This way, the type of redController is Red. When storing subclasses of a certain class in a collection whose type is the superclass, type information is never lost, so you can access the specific subclass properties after casting the specific array element to the subclass it is from.