Set data on PrimaryContentViewController and DrawerContentViewController from my HomeViewController - ios

I am using Pulley where I am using below code to open the PulleyViewController.
func openEventInfoPage(event : EventsModel,indexPath:NSIndexPath){
let vc = storyboard?.instantiateViewController(withIdentifier: "PulleyViewController")
as! PulleyViewController
navigationController?.pushViewController(vc, animated: true)
}
Here, while opening the PulleyViewController I also need to send data to both DrawerContentViewController and PrimaryContentViewController. How should I do that?
Its nowhere mentioned on Github, I tried making object of both the classes and sending data before Pushing PulleyViewController but it didn't work. Thanks in advance.

I came out with the following solution and it worked perfectly.
let mainContentVC = storyboard?.instantiateViewController(withIdentifier: "PrimaryContentViewController") as! PrimaryContentViewController
mainContentVC.event = event
mainContentVC.indexPath = indexPath
let drawerContentVC = storyboard?.instantiateViewController(withIdentifier: "DrawerContentViewController") as! DrawerContentViewController
drawerContentVC.event = event
let pulleyDrawerVC = PulleyViewController(contentViewController: mainContentVC, drawerViewController: drawerContentVC)
navigationController?.pushViewController(pulleyDrawerVC, animated: true)

Add a property on DrawerContentViewController. like - aProperty as open property. And assign value of aProperty on your DrawerContentViewController -
func openEventInfoPage(event : EventsModel,indexPath:NSIndexPath){
let vc = storyboard?.instantiateViewController(withIdentifier: "PulleyViewController") as! PulleyViewController
let vc2 = storyboard?.instantiateViewController(withIdentifier: "DrawerContentViewController") as! DrawerContentViewController
vc2.aProperty = "value"
navigationController?.pushViewController(vc, animated: true)
}

Related

Swift problem with sending data to another ViewController

Variable cards in second ViewController should be updated in first VC on buttonClick.
I tested the sending data from the first VC with printing data and it works good.
Here is the code:
#IBAction func btnTapped(_ sender: Any) {
let mainStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let secondVC = (mainStoryboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController)
for card in setsOfCardsByLevel {
cardVC.cards.append(card)
}
print("Number of cards to send - \(cardVC.secondVC.count)") //PRINTS RIGHT NUMBER
presentVC("SecondViewController") //WORKS FINE
}
Maybe you dont need this method below but I will put it just in case:
func presentVC(_ VC_Name: String) {
guard let myVC = self.storyboard?.instantiateViewController(withIdentifier: VC_Name) else { return }
let navController = UINavigationController(rootViewController: myVC)
navController.modalPresentationStyle = .fullScreen
self.navigationController?.present(navController, animated: true, completion: nil)
}
PROBLEM: When I print cards in the secondViewController, they are empty(count = 0). How?
EDIT: While waiting for answer on StackOverflow I changed presentViewController to pushViewController and print in secondVC shows right number. I am confused.
Your problem is in your presentVC method. First in your btnTapped method you instantiate your second viewController and assing your cards, again in your presentVC method instantiate another controller and it's not relevant to the first you define in your btnTapped and cards variable not assigned. For solution you can pass your secondVC as a parameter to your presentVC, not the name of storyboard

passing data from 2 view controllers without segue

I have a mainviewcontroller and a popup view controller which opens without a segue.
the popup viewcontroller recive data from Firebase, and then i need to append this data to an array in the mainviewcontroller.
How can i do that?
(i tried to create a property of the popupviewcontroller in the mainviewcontroller, but in crashes the app)
this is the code that opens the popup:
#IBAction func showPopUp(_ sender: Any) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbPopUp") as! PopUpViewController
self.addChild(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
You need to connect the classes so that the popup class knows what to do with the data once it has been received. Here's a sample structure that works in a playground that you should be able to apply to your real classes.
class MainClass {
func showPopUp() {
let popOverVC = PopUpClass()
popOverVC.update = addToArray
popOverVC.receivedData()
}
func addToArray() {
print("Adding")
}
}
class PopUpClass {
var update: (()->())?
func receivedData() {
if let updateFunction = update {
updateFunction()
}
}
}
let main = MainClass()
main.showPopUp()
Or you could create a global variable so it can be accessed anywhere. ... It is better to pass data but I just thought it would be easier in this instance, so the variable can be accessed anywhere in your entire project.
if it is just a notification, you can show it in an alert, but if you don't want to use an alert my offer to present another view controller is not like this , try my code :
//if you have navigation controller ->
let vc = self.storyboard?.instantiateViewController(
withIdentifier: "storyboadrID") as! yourViewController
self.navigationController?.pushViewController(vc, animated: true)
//if you don't use navigation controller ->
let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "storyboadrID") as! yourViewController
self.present(VC1, animated:true, completion: nil)
also if you want to pass any data or parameter to destination view controller you can put it like this before presenting your view controller :
VC1.textView.text = "test"

Using storyboard?.instantiate returns "Unexpectedly found nil" error

I am getting an error when I use storyboard?.instantiate. It's giving me this error:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
and this is my code:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "SelectedViewController")
as? SelectedViewController
vc?.name = imgArr[indexPath.row]
self.navigationController?.pushViewController(vc!, animated: true)
}
and I am already using the identifier ID in this photo:
Please anyone can help me in this issue.
Move the mouse over the class field in IB , then click enter , module check must be ticked , and verify you correctly set storyboard identifier
is SelectedViewController in the same storyboard of the collection view's view controller?
I always prefer to unwrap optionals with a guard or if let to avoid crashes like this. You can use:
guard let viewController = storyboard?.instantiateViewController(withIdentifier: "SelectedViewController") as? SelectedViewController else { "return error here if wanted" return }
viewController.name = imgArr[indexPath.row]
self.navigationController?.pushViewController(viewController, animated: true)
try this below code:
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vcTitles = storyBoard.instantiateViewController(withIdentifier: "vcTitles") as! VCTitlesViewController
self.navigationController?.pushViewController(vcTitles, animated: true)

Swift: Reuse code passing class to parameter

I would like to reuse code, so I created redirectToTabBarControllerChild
func redirectToTabBarControllerChild(storyboardName: String, tabBarIndex: Int, segueID: String, viewController: UITableViewController) {
let storyboardMain = UIStoryboard(name: storyboardName, bundle: nil)
let tabBarController = storyboardMain.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController
window?.rootViewController = tabBarController
tabBarController.selectedIndex = tabBarIndex
let navigationViewContrller = tabBarController.childViewControllers[tabBarIndex] as! UINavigationController
let currentViewContrller = navigationViewContrller.childViewControllers.first as! viewController
currentViewContrller.performSegue(withIdentifier: segueID, sender: nil)
window?.makeKeyAndVisible()
}
The last parameter I would like to pass ProfileViewController for example. But I have an error in this line: let currentViewContrller = navigationViewContrller.childViewControllers.first as! viewController
Use of undeclared type viewController
Does anyone know how I could do it?
The navigationController?.childViewControllers is an array of UIViewControllers. You´re getting the first property which means you need to cast it to as! UIViewController which will force cast it and it will not be an optional anymore.
What you want to do is to cast it to a UITableViewController, so do it like this:
if let vc = navigationViewContrller.childViewControllers.first as? UITableViewController {
// Will succeed if the first is of type UITableViewController
// Use vc in here
}
Replace viewController to UITableViewController

return UIViewController from a class function

In my Restaurant model I have a function, that returns UINavigationController, I've implemented it to make my code more readable. But I am curious if it is ok to do it this way, or should I make a function of UIViewController, that takes Restaurant as a parameter.
func reserveTable(timeIndex: Int) -> UINavigationController {
let storyBoard = UIStoryboard(name: "Reservations", bundle: nil)
let targetVC = storyBoard.instantiateViewController(withIdentifier: "bookingNC") as! UINavigationController
let destinationVC = targetVC.topViewController as! BookingViewController
destinationVC.availabeleDates = self.schedule
destinationVC.timeRange = self.avaliableTimes
destinationVC.restaurantId = self.id
destinationVC.requestedTimeIndex = timeIndex
destinationVC.reservationType = "Бронирование"
return targetVC
}
I would do this differently, your model is supposed to handle data, not Views.
There are many ways in which you could do this, personally I would have a property on the booking controller for the reservation. Then you could just do something like:
let vc = BookingViewController()
vc.reservation = reservation
self.present(vc, animated: true)
wherever you needed to present the booking controller. Ensuring you have a reservation first.
In your init/viewDidLoad method of the BookingViewController you can do alot of the work above...
override func viewDidLoad() {
super.viewDidLoad()
if let reservation = self.reservation {
self.availabeleDates = reservation.schedule
self.timeRange = reservation.avaliableTimes
self.restaurantId = reservation.id
self.requestedTimeIndex = timeIndex
self.reservationType = "Бронирование"
}
}

Resources