Pass String Variable Data from one Class/ViewController to Class/ViewController - ios

I have two viewControllers:
1. CheckoutVC
2. DeliveryTimeVC
In DeliveryTimeVC I have the following variable:
class DeliveryTimeVC: UIViewController {
var tableViewDay:String = ""
}
I use the following push to go from CheckoutVC to DeliveryTimeVC:
let storyboard = UIStoryboard(name: Storyboard.DeliveryTimeStoryboard, bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: StoryboardId.DeliveryTimeVC)
navigationController?.pushViewController(controller, animated: true)
In DeliveryTimeVC I have a tableView where on didSelect I go back to CheckoutVC and in didSelect func I have the following code to append my variable before leaving the controller:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableViewDay.removeAll()
tableViewDay.append(cell.weekDayLbl.text!)
navigationController?.popViewController(animated: true)
}
How can I transfer the String variable data from DeliveryTimeVC to another variable in CheckoutVC? Lets say I create a variable in CheckoutVC as:
class CheckoutVC: UIViewController, CartProductCellDelegate {
var tableViewDayTransferedData:String = ""
}
How can I transfer the data from tableViewDay:String to tableViewDayTransferedData:String

well you can use this lines
let storyboard = UIStoryboard(name: "NAMEOFYOURSTORYBOARD", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "IDOFYOURVIEW") as! CheckoutVC
vc.tableViewDayTransferedData = self. tableViewDay
self.navigationController!.pushViewController(vc, animated: true)

Based on #Hassan Shahbazi comment above I was able to change his code slightly and get the final answer that works for me:
protocol DeliveryTimeDelegate: class {
func didGetData(tableViewDayTransferedData: String)
}
class DeliveryTimeVC: UIViewController {
weak var delegate: DeliveryTimeDelegate?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableViewDay.removeAll()
tableViewDay.append(cell.weekDayLbl.text!)
delegate?.didGetData(tableViewDayTransferedData: tableViewDay)
navigationController?.popViewController(animated: true)
}
}
class CheckoutVC: UIViewController, DeliveryTimeDelegate {
func ...() {
let storyboard = UIStoryboard(name: Storyboard.DeliveryTimeStoryboard, bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: StoryboardId.DeliveryTimeVC) as! DeliveryTimeVC
controller.delegate = self
navigationController?.pushViewController(controller, animated: true)
}
func didGetData(tableViewDayTransferedData: String) {
tableViewDayTransferedData = tableViewDayTransferedData
}
}
in the last func you see two same variables; they just have the same name: tableViewDayTransferedData = tableViewDayTransferedData first one is from CheckoutVC. the second one is from the protocol.

There are generally 2 main patterns for data/variable passing in iOS.
Delegate Pattern
The popular pattern for Objective-c days, but still useful and easy to do. You'll need to define a delegate protocol and use it for passing variables.
protocol DeliveryTimeDelegate: class {
func didGetData(tableViewDay: String)
}
class DeliveryTimeVC: UIViewController {
weak var delegate: DeliveryTimeDelegate?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableViewDay.removeAll()
tableViewDay.append(cell.weekDayLbl.text!)
delegate?.didGetData(tableViewDay: "YOUR_VALUE")
navigationController?.popViewController(animated: true)
}
}
class CheckoutVC: UIViewController, CartProductCellDelegate {
func ...() {
let storyboard = UIStoryboard(name: Storyboard.DeliveryTimeStoryboard, bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: StoryboardId.DeliveryTimeVC)
controller.delegate = self
navigationController?.pushViewController(controller, animated: true)
}
}
extension CheckoutVC: DeliveryTimeDelegate {
func didGetData(tableViewDay: String) {
tableViewDayTransferedData = tableViewDay
}
}
Closure Pattern
The pattern could be seen as the swift friendly implementation of delegate. It's important to pay enough attention to memory management and retain cycle issues when you're using closure.
class DeliveryTimeVC: UIViewController {
var onDataTransfered: ((String) -> Void)?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableViewDay.removeAll()
tableViewDay.append(cell.weekDayLbl.text!)
self.onDataTransfered?("YOUR_VALUE")
navigationController?.popViewController(animated: true)
}
}
class CheckoutVC: UIViewController, DeliveryTimeDelegate {
func ...() {
let storyboard = UIStoryboard(name: Storyboard.DeliveryTimeStoryboard, bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: StoryboardId.DeliveryTimeVC)
controller.onDataTransfered = { [weak self] tableViewDayTransferedData in
self?.tableViewDay = tableViewDayTransferedData
}
navigationController?.pushViewController(controller, animated: true)
}
}

Related

Reusable UITableViewController

I want to avoid duplicate rewriting same code and create reusable UITableViewController.
I have ExerciseViewController with 3 buttons. Each button push a UITableViewController on the navigation stack. There are three UITableViewControllers: 1) CategoryUITableVC, 2) EquipmentUITableVC, 3) MusclesUITableVC.
All of these three view controllers have almost exactly same layout - cells with labels and accessory buttons. The only difference is that first view controller has got image next to title. Is it worth doing one reusable VC and instantiate it 3 times or maybe better solution create 3 separated VC (but It will be just rewriting almost same code).
I use coordinator pattern.
class ExerciseCoordinator: NSObject, Coordinator {
var childCoordinators = [Coordinator]()
var navigationController: UINavigationController
...
//unnecessary code to show
...
// *HERE I INSTANTIATE VIEW CONTROLLERS, I PRESENT THEM MODALLY BUT I WANT TO HAVE NAVIGATION BAR, SO I NEED TO CREATE NEW NAVIGATION CONTROLLERS*
lazy var equipmentVC: ReusableTableViewController = {
let vc = AppStoryboard.Main.instantiate(ReusableTableViewController.self)
vc.delegate = self
return vc
}()
lazy var equipmentNavController: UINavigationController = {
let navController = UINavigationController(rootViewController: equipmentVC)
navController.navigationItem.largeTitleDisplayMode = .always
return navController
}()
lazy var categoryVC: ReusableTableViewController = {
let vc = AppStoryboard.Main.instantiate(ReusableTableViewController.self)
vc.delegate = self
return vc
}()
lazy var categoryNavController: UINavigationController = {
let navController = UINavigationController(rootViewController: categoryVC)
navController.navigationItem.largeTitleDisplayMode = .always
return navController
}()
lazy var muscleVC: ReusableTableViewController = {
let vc = AppStoryboard.Main.instantiate(ReusableTableViewController.self)
vc.delegate = self
return vc
}()
lazy var muscleNavController: UINavigationController = {
let navController = UINavigationController(rootViewController: muscleVC)
navController.navigationItem.largeTitleDisplayMode = .always
return navController
}()
}
extension ExerciseCoordinator: CustomExerciseDelegate {
func selectCategory() {
navigationController.viewControllers.last?.present(categoryNavController, animated: true, completion: nil)
categoryVC.dataType = .category
}
func selectEquipment() {
navigationController.viewControllers.last?.present(equipmentNavController, animated: true, completion: nil)
equipmentVC.dataType = .equipment
}
func selectMuscles() {
navigationController.viewControllers.last?.present(muscleNavController, animated: true, completion: nil)
muscleVC.dataType = .muscle
}
}
I assign data type to know from where it comes from (CategoryVC/EquipmentVC/MuscleVC) when I will dismiss UITableVC.
Here it is my reusable UITableViewController:
import UIKit
import RealmSwift
class ExerciseCategoryTableViewController: UITableViewController {
var delegate: ExerciseSelectionCriteriaDelegate?
//I use it delegate to send data back after dismiss view
var dataType: DataType?
var data = [String]() {
didSet {
DispatchQueue.main.async {
self.tableView.reloadData() }}
}
override func viewDidLoad() {
super.viewDidLoad()
getData()
}
func getData() {
if dataType == .category {
let allCategories = RealmService.shared.realm.objects(Category.self)
data = allCategories.compactMap({$0.category})
} else if dataType == .equipment {
let allEquipment = RealmService.shared.realm.objects(Equipment.self)
data = allEquipment.compactMap({$0.equipment})
} else {
let allMuscles = RealmService.shared.realm.objects(Muscles.self)
data = allMuscles.compactMap({$0.muscles})
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// below is my own shortcut for dequeue cell, it works
let cell: ExerciseSelectionTableViewCell = tableView.dequeueResuableCell(for: indexPath)
cell.category.text = data[indexPath.row]
if let image = UIImage(named: "\(data[indexPath.row].lowercased())") {
cell.categoryImage.image = image
cell.categoryImage.isHidden = false
} else {
cell.categoryImage.isHidden = true
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 70
}
#IBAction func closeViewController(_ sender: UIBarButtonItem) {
closeViewController()
}
#IBAction func saveSelectedCategories(_ sender: UIBarButtonItem) {
saveSelectedData()
}
func saveSelectedData() {
let selectedIndexes = tableView.indexPathsForSelectedRows
if let selectedData = selectedIndexes?.compactMap({data[$0.row]}) {
dismiss(animated: true) {
self.delegate?.selectedFields(for: selectedData, dataType: self.dataType)
}
} else {
dismiss(animated: true) {
self.delegate?.selectedFields(for: nil, dataType: self.dataType)
}
}
}
func closeViewController() {
guard let _ = tableView.indexPathsForSelectedRows else { return dismiss(animated: true, completion: nil)}
Alert.showAlertWithCompletion(on: self, with: "TEXT", message: "TEXT") { _ in
self.dismiss(animated: true, completion: nil)
}
}
}
I will be thankful if you tell me if this approach is correct or maybe better solution are separated view controllers or create protocol with default implementation?

Crashing when changing label text

I'm trying to set a label depending on the UserDefault value but It's crashing with the error:
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file
So, first time I run it the app does NOT crash using this code:
MainActivity
override func viewDidLoad() {
super.viewDidLoad()
getAllVehicles()
}
func getAllVehicles(){
let defaults = UserDefaults.standard
if defaults.object(forKey: "currentCar") != nil{
currentCar = defaults.string(forKey: "currentCar")
registrationPlate.text = currentCar
}
}
So the application is setting the label to it's UserDefault and that does work, but when I'm trying to change it (Just to mention, it's from another class/viewcontroller)
ChooseCarViewController
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let car = carsArray[indexPath.row]
let defaults = UserDefaults.standard
defaults.set(car, forKey: "currentCar")
if let storyboard = storyboard{
let vc = storyboard.instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
vc.getAllVehicles()
self.dismiss(animated: true)
}
}
So by any reason I can NOT change the name when calling the method.
I've also tried to set it directly by using
vc.registrationPlate.text = car
Just to mention:
I've tried to print out "car" and it does return the correct value.
I've also tried to print the "currentCar" in MainActivity after calling the method and It's returning the correct car. But the textfield cannot be changed because of unwrapping an Optional value.
All UI stuff that you build with storyboard are optional and they are implicitly unwrapped using !. For example
#IBOutlet weak var registrationPlate: UILabel! // <- Do you see the `!` here?
So as UIViewController default template suggests, you should
Do any additional setup after loading the view.
The first function you can do it in is viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
If you initialize a view controller from another one it doesn't grantees that all outlets are automatically have been assigned (yet).
First of all you must use the initializer from the storyboard or from the xib file to have the correct initializer set the outlets.
Then you should wait for viewDidLoad. (You can use vc.loadView() to force it, but it's not recommended at all)
In your code, you are using storyboard.instantiateViewController... that creates another instance and since you are just dismissing the view, it's not needed at all! Because the previous controller is already loaded and it exist in the memory.
And note that you are using reading the registrationPlate inside getAllVehicles and it should be done after view is loaded. So you can extract this part from it and move it somewhere after view gets loaded.
Do not misuse UserDefaults to share data between controllers, pass the data directly.
The crash occurs because the outlet is not connected yet when the label is accessed.
The solution is to create a temporary variable in MainActivity and assign the value to the label in viewDidLoad
var currentCar = ""
override func viewDidLoad() {
super.viewDidLoad()
registrationPlate.text = currentCar
}
Assign the car to the temporary variable in ChooseCarViewController and you have to present the vc
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let car = carsArray[indexPath.row]
UserDefaults.standard.set(car, forKey: "currentCar")
if let vc = storyboard?.instantiateViewController(withIdentifier: "MainViewController") as? MainViewController {
vc.currentCar = car
present(vc, animated: true, completion: nil)
self.dismiss(animated: true)
}
}
You want to use the protocol / delegate pattern.
Define a protocol:
protocol ChangeCarDelegate: AnyObject {
func changeCar(_ newCar: String)
}
Have your Main view controller "conform" to that protocol:
class MainViewController: UIViewController, ChangeCarDelegate {
func changeCar(_ newCar: String) {
currentCar = newCar
registrationPlate.text = currentCar
}
}
When you present the Choose Car VC, assign its ChangeCarDelegate property:
#IBAction func showChooseCar(_ sender: Any) {
if let vc = storyboard?.instantiateViewController(withIdentifier: "ChooseCarVC") as? ChooseCarViewController {
vc.changeCarDelegate = self
present(vc, animated: true, completion: nil)
}
}
Or, if you are using a Storyboard created Segue to present the Choose Car VC:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? ChooseCarViewController {
vc.changeCarDelegate = self
}
}
When you select a car from the table, tell the delegate of the new selection:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let car = carsArray[indexPath.row]
let defaults = UserDefaults.standard
defaults.set(car, forKey: "currentCar")
// communicate with the delegate
changeCarDelegate?.changeCar(car)
dismiss(animated: true, completion: nil)
}
Here is a full set of classes for a simple "Main" VC with a label and a button. Tapping the button presents "ChooseCar" VC, which has a table of cars.
protocol ChangeCarDelegate {
func changeCar(_ newCar: String)
}
class MainViewController: UIViewController, ChangeCarDelegate {
#IBOutlet var registrationPlate: UILabel!
var currentCar: String = ""
override func viewDidLoad() {
super.viewDidLoad()
getAllVehicles()
}
func getAllVehicles(){
let defaults = UserDefaults.standard
if defaults.object(forKey: "currentCar") != nil{
currentCar = defaults.string(forKey: "currentCar") ?? ""
registrationPlate.text = currentCar
}
}
#IBAction func showChooseCar(_ sender: Any) {
if let vc = storyboard?.instantiateViewController(withIdentifier: "ChooseCarVC") as? ChooseCarViewController {
vc.changeCarDelegate = self
present(vc, animated: true, completion: nil)
}
}
// or, if you are using a Storyboard created Segue to present the Choose Car VC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? ChooseCarViewController {
vc.changeCarDelegate = self
}
}
func changeCar(_ newCar: String) {
currentCar = newCar
registrationPlate.text = currentCar
}
}
class ChooseCarViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
weak var changeCarDelegate: ChangeCarDelegate?
#IBOutlet var tableView: UITableView!
var carsArray: [String] = [
"Ford",
"Honda",
"Toyota",
"Chrysler",
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return carsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CarCell", for: indexPath)
cell.textLabel?.text = carsArray[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let car = carsArray[indexPath.row]
let defaults = UserDefaults.standard
defaults.set(car, forKey: "currentCar")
changeCarDelegate?.changeCar(car)
dismiss(animated: true, completion: nil)
}
}
As you have mentioned this in your comments!!
#TejaNandamuri So how can that be fixed? Using ViewDidAppear?
But how comes it's not loaded since the ViewController is still in the back stack right?
In this code, vc is not pointing to the same view controller which is behind in the stack. It is creating a new view controller. In new vc, textfield is not yet loaded.
if let storyboard = storyboard{
let vc = storyboard.instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
vc.getAllVehicles()
self.dismiss(animated: true)
}
Use delegates to achieve what you want.
You are trying to assigning a nullable value to label, handle null using guard let or if let
like below
guard let currentCar = defaults.string(forKey: "currentCar") else{
registrationPlate.text = ""
return
}
registrationPlate.text = currentCar ?? ""

TableView Cell Selection not working properly

Trying MVVM design pattern.
Created a tableView in storyboard and in FirstViewController added below code :
#IBOutlet weak var menuTblView: UITableView!
let menuViewModel = MenuTableViewModel()
override func viewDidLoad() {
super.viewDidLoad()
self.menuTblView.dataSource = menuViewModel
self.menuTblView.delegate = menuViewModel
menuViewModel.delegate = self
menuTblView.register(UINib.init(nibName: "MenuTableViewCell", bundle: nil), forCellReuseIdentifier: "MenuTableViewCell")
menuTblView.separatorStyle = .none
}
and created a MenuTableViewModel having the tableviewDelegate and tableViewDatasource methods.
In MenuTableViewModel added the didSelectRowAt:
extension MenuTableViewModel:UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate.present()
}
}
protocol MenuTableViewModelDelegate : class {
func present()
}
and created a prototcol to present a SecondViewController.
In FirstViewController added below code:
extension FirstViewController : MenuTableViewModelDelegate {
func present() {
let asd = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.present(asd, animated: true, completion: nil)
}
}
The problem is the SecondViewController appears after clicking the tableViewCell twice.
EDIT:
MenuTableViewModel code :
class MenuTableViewModel: NSObject {
var delegate:MenuTableViewModelDelegate!
}
and in FirstViewController - ViewDidLoad added :
menuViewModel.delegate = self
Thanks #koropok for the solution. Added below code and it worked :
DispatchQueue.main.async {
self.delegate.present()
}
but why I have to do this.
Infact If I am adding below code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
//DispatchQueue.main.async {
self.delegate.present()
//}
}
then also it's working fine.
My approach is wrong or I am missing something here.

Pass Data using a pushViewController?

Using this code I am able to 'segue' to the same instance of my view controller
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "DetailVC")
self.navigationController?.pushViewController(vc, animated: true)
}
However, how do I pass data over? I only know how to pass data using the segue option. When I run the code with this, I get nil errors because the new instantiated view controller cannot read the data.
for example I add here, for detail description you can get the tutorial from here
class SecondViewController: UIViewController {
var myStringValue:String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// We will simply print out the value here
print("The value of myStringValue is: \(myStringValue!)")
}
and send the string as
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "DetailVC") as! SecondViewController
vc.myStringValue = "yourvalue"
self.navigationController?.pushViewController(vc, animated: true)
}
First off. This isn't a segue. This is just pushing another view to the stack. And (like Ashley Mills says) this is not the same instance you are currently in. This is a NEW instance of a view controller.
But all you need to do is populate the data. You already have the controller here...
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// you need to cast this next line to the type of VC.
let vc = storyboard.instantiateViewController(withIdentifier: "DetailVC") as! DetailVC // or whatever it is
// vc is the controller. Just put the properties in it.
vc.thePropertyYouWantToSet = theValue
self.navigationController?.pushViewController(vc, animated: true)
}
Then in your second view controller catch the value like this
class DetailVC: UIViewController {
var thePropertyYouWantToSet = String()
override func viewDidLoad() {
print(thePropertyYouWantToSet)
}
}
What you're using isn't a segue. This is just pushing a NEW instance (not the same one) of view controller onto the nav stack.
To segue, in your storyboard, you can just drag a link from the collection view cell to the view controller, then assign data in the prepareForSegue method…
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let viewController = segue.destinationViewController as? DetailVC {
viewController.someProperty = self.someProperty
}
}
In DetailVC, Create a variable and assign value while you create an object. Check example below:
class DetailVC {
var dataString: String?
}
Pass data like below:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "DetailVC") as! DetailVC
vc.dataString = "PASS THE DATA LIKE THIS"
self.navigationController?.pushViewController(vc, animated: true)
}
If you're following the no storyboard pattern you can do it like this
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let viewController = NextViewController()
viewController.dataInsideNextViewController = "Data to be passed"
navigationController?.pushViewController(viewController, animated: true)
}
In your ViewController1 launch your ViewController2 using these code
Class ViewController1: UIViewController {
var dataFromVC2 = ""
func loadVC2() {
let vc2 = ViewController2()
vc2.dataFromVC1 = "Hi VC2"
vc2delegate = self
navigationController?.pushViewController(vc2, animated: true)
}
}
In your ViewController2, add this code. You can use the delegate property to pass back data from ViewContoller2.
Class ViewController2: UIViewController {
var dataFromVC1: String = ""
weak var delegate: ViewController1!
func passData_toVC1() {
delegate.dataFromVC2 = "How's it going VC1?"
}
}

Data not appearing in view controller

I have been trying everything I could but nothing seems to work. I am trying to pass firebase user information from one view controller to another, but it never appears.
It starts from a table view
The table view is populated with users that are being pulled from my firebase database. When the user selects a cell the following code gets executed:
I reference function "showProfileControllerForUser" as a way to transport the data of the cell that was selected
var mainProfile: userProfileNavigator?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let user1 = self.users[indexPath.row]
self.mainProfile?.showProfileControllerForUser(user3: user1)
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc: UINavigationController = storyboard.instantiateViewController(withIdentifier: "mainNavProfile") as! UINavigationController
self.present(vc, animated: true, completion: nil)
}
In "userProfileNavigator" is where the function that was used before is. The function passes the information that was collected and passes that to the final destination.
func showProfileControllerForUser(user3: User){
mainProfile?.user2 = user3
}
Finally, "mainProfile" is where I want the data to be passed to.
var user2: User?{
didSet{
navigationItem.title = user2?.name
}
I could imagine this being very confusing, I can provide anymore information or clarity if needed
attempted to setup table as such:
var mainProfile: mainProfile?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let user1 = self.users[indexPath.row]
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc: UIViewController = storyboard.instantiateViewController(withIdentifier: "mainProfile")
self.mainProfile?.user2 = user1
self.present(vc, animated: true, completion: nil)
}
And the ViewController in which the information is being passed as such:
import UIKit
import Firebase
class mainProfile: UIViewController{
#IBOutlet weak var testLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
print("lets see if this is the new user", user2.name as Any)
}
var user2 = User()
}
but it still comes up as "nil"
If I understood your question right, then you have two ViewControllers. One which contain UITableView, and another is ShowProfileControllerForUser.
In ViewController which contain UITableView, code this:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let user1 = self.users[indexPath.row]
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc: UINavigationController = storyboard.instantiateViewController(withIdentifier: "mainNavProfile") as! UINavigationController
vc.user3 = user1
self.present(vc, animated: true, completion: nil)
}
Also, I am not sure if you're presenting the right ViewController.
In your ShowProfileControllerForUser.swift,
var user3 = User // declare a variable with proper type.
Now in your viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
showProfileControllerForUser(user3)
}
Edit:
var mainProfile: mainProfile?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let user1 = self.users[indexPath.row]
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc: UIViewController = storyboard.instantiateViewController(withIdentifier: "mainProfile")
//self.mainProfile?.user2 = user1 // Instead of this line
vc.user2 = user1 // use this line
self.present(vc, animated: true, completion: nil)
}
If you want to open controller with that passed value, you can set that value after instantiating it
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc: UINavigationController = storyboard.instantiateViewController(withIdentifier: "mainNavProfile") as! UINavigationController
// this is what your showProfileControllerForUser doing
vc.user2 = user1
self.present(vc, animated: true, completion: nil)

Resources