This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 5 years ago.
I want to initData for two view controllers that I don't want to present immediately.
Atm I have when a user taps a tableViewCell (select a group) they are presented with "chatVC" and the appropriate data is presented. In ChatVC the user can access two other VC, ChatInfoVC and ChatInfoSettingsVC. Is there a way to pass the right info from the tableViewCell (the group as I do when I present the ChatVC) to both the other VC? I'm pulling all data from Firebase.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let chatVC = storyboard?.instantiateViewController(withIdentifier: "chat") as? ChatVC else { return }
chatVC.initData(forGroup: groupsArray[indexPath.row])
presentDetail(chatVC)
}
I appreciate all help.
Typically your ChatVC will provide the data to the viewcontrollers it presents. Therefore, you'd have to either
hand that data from the current viewcontroller to ChatVC and from there further to the next two viewcontrollers, or
fetch the detail data in ChatVC before presenting the two other viewcontrollers
You could also intantiiate those two viewcontrollers in tableView(_:didSelectRow:), provision them with the correct data, and then store those viewcontrollers in two properties of your ChatVC -- but this seem to me somehow strange
Option
A: store your VC in class property, assign it before presenting it in the didselectRow.
B: create a class property to store the indexpath of the selected one. Your VC data is inside groupsArray, u just need the indexpath to get it. Then get data, init controller, assign that data to it.
If I m not misunderstand you, you can just store the data to the ChatVc(declare a store property in ChatVc), when you ready to present the other two ViewControllers you can easily access the data.
Related
Suppose I have a SWIFT app and it contains a UIViewController with a table. The table of course has prototype UITableViewCells. The information contained in the cell can be one of two internal object types, lets say Widget and Sprocket. Widget and Sprocket are objects that derive from the same base class Thing.
My table will be a list of Things, where each Thing is either a Widget or a Sprocket. What I want to happen is that if a user selects a table cell that is a Widget, it should show a details ViewController for a Widget, ie WidgetViewController. If however the user selects a Sprocket then the app should show a SprocketViewController.
How exactly can I make this happen? My understanding is that if I go into the storyboard and click-drag to make a segue from the main VC to either WidgetViewController or SprocketViewController then that segue will occur in the app automagically, ie without me adding any code. So if I click-drag to create two such segues then I have no idea what will happen but I assume that the app will crash from trying to call both segues.
The problem I am facing is that my current app has a WidgetTableViewController with a storyboard segue to a WidgetViewController and also has a SprocketTableViewController with a storyboard segue to a SprocketViewController, but now I have to put Widgets and Sprockets into the same VC (ie ThingTableViewController) and have the app conditionally launch either WidgetViewController or SprocketViewController.
So how do I do this?
One way to do this could be:
In the tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) function of your UITableViewDelegate check if the selected cell corresponds to an object Widget or an object Sprocket
Then, present the corresponding UIViewController with the necessary configuration with this code:
let vc = UIStoryboard(name: "The name of your storyboard here", bundle: nil).instantiateViewController(withIdentifier: "Your VC identifier") as! YourViewController
// pass your data and configure the viewcontroller here
navigationController?.pushViewController(vc, animated: true)
In storyboard, assign the identifier that you think is convenient to your ViewController:
Select the ViewController -> 3rd item -> Identity -> StoryboardId and check "Use Storyboard ID"
Note: Delete the segues what are you currently using
1) To configure you cells you have your DataSource. So basically you could just configure your tableView with array of structures like this.
struct ViewModel {
var type: CellType
...
}
When you tap your cell with type you could easily find what detail controller you need.
2) In didSelectRow you cold get tapped cell
let cell = tableView.cellForRow(at: indexPath)
and than just check if its is WidgetsCell or SprocketsCell
I have login few screens and controllers in my app. First screen is screen with button and moves user to next login view with username, password field and login button. On the controller i have function onClickButton and when i have good data i request to the server with this data.
When server give me callback i have many params about user to set in label in next view.
My structure is like this
Login View -> SecondLogin View and LoginViewController -> TabBarController -> NavigationController -> Table View with TableViewController
My code is
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "afterLoginView" {
if let secondVC = segue.destination as? TabBarViewController {
secondVC.finalName = self.username
}
}
}
When i want transfer my data directly to tableViewController i have error
Thread 1: signal SIGABRT
I do not understand what I'm doing wrong
You'll need these values in almost all view controllers. Create a singleton class to store the logged in user values like this
class UserDetails: NSObject, Codable {
static let shared = UserDetails()
private override init() {
super.init()
}
var finalName: String?
var otherDetails: String?
}
Now when you receive the response from the login api, assign the values in this singleton class.
UserDetails.shared.finalName = "something"//Name received from server callback
Now you can access these values from any view controller.
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
print(UserDetails.shared.finalName)
}
}
You have some work to do to get to the right view controller. Since your segue is only pointing at the UITabBarViewController, you should put in another guard or if/let statement to get you to the UINavigationController, and then another to finally get you to the UITableViewController, where you can actually refer to your finalName variable.
That would look something like:
if let secondVC = segue.destination as? TabBarViewController {
if let navCon = secondVC.viewController[0] as? UINavigationController {
if let tableVC = navCon.topViewController as? nameOfYourTableVC {
tableVC.finalName = self.username
}
The code is untested, just typed off the top of my head, so please proceed with due caution. Issues such as which tab is the correct NavController would also need to be addressed.
You need to use the actual name of your tableView class in that last if/let. A generic UITableViewController will not include your custom variables.
When server give me callback i have many params about user to set in label in next view.
This is a great example of why you should keep the M in MVC. When you get a response back from the server, store the returned data in your data model. (If you don't have a data model, you should make one.) When a view controller gets some data from the user, such as a user name, it should store that in the model. There's little reason to pass raw data back and forth between view controllers directly... just make sure that all your view controllers have a reference to the model, and have them get and set values there as needed.
This kind of approach will make your code a lot more flexible. It allows view controllers to worry about what they need to do their job, and it gets them out of the business of caring what other view controllers need.
My structure is like this
Login View -> SecondLogin View and LoginViewController -> TabBarController -> NavigationController -> Table View with TableViewController
It might make more sense to load the tab bar controller and then present the login view controller(s) modally. The view controllers that are managed by the tab bar controller can all be set up to refuse to do anything useful until the data they need is present in the data model, and that lets the tab bar controller be the root view controller. That will make it easy to set the model for each of it's child view controllers when the app starts up, and the app can then present the modal login view controllers, also set up with references to the model.
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.
I have a storyboard view embedded in a navigation controller that displays a record from a database along with a link to view a related record. The related record needs to use the same view to display its data while still maintaining a navigation stack so the user can go back to the previous record. Keeping in mind that some data needs to be passed to the new viewController and the UI is composed of a tableView with each element in a row, how can this segue be accomplished?
Below is the view. If possible, please respond with any sample code in Swift.
With some inspiration from this answer and guidance by #Jassi, here is the final product:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let vc = storyboard?.instantiateViewControllerWithIdentifier("inventoryItemDetail") as InventoryDetail
vc.fmRecordId = item["inContainerRecordId"]! //this is the data which will be passed to the new vc
self.navigationController?.pushViewController(vc, animated: true)
}
An idea-
Give the view controller an identifier. And override the below function.
prepareForSegue
In that function instantiate the view controller using the identifier you have and then pass the necessary data to that controller. And push it on navigation controller.
I hope it will work.
I started learning App development in Swift recently and I'm still fairly new. I'm trying to make an app where at the home screen, the user will click a button called profiles, and it'll show a list of names in a tableViewController. When the user clicks a name it'll open up the person's profile in a viewController.
I'm stuck so far on what method and what to code in that method to allow the user to click on the list of names in my TableViewController and then open up a viewController for that person. I've already created my other viewController (DetailsViewController) and created a segue between the TableViewController and the DetailsViewController.
I've been searching for a long time on how to do this but couldn't find any luck. If someone could just point me in the right direction that'd be great.
You have to create the segue from the cell to the detail view controller. To provide the detail controller with the data, give it a property (e.g. name) that you can set in prepareForSegue which you override in the parent controller.
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
let cell = sender as UITableViewCell // or your cell subclass
let indexPath = self.tableView.indexPathForCell(cell)
let name = dataArray[indexPath.row]
// or something else depending on the structure of your data model
let controller = segue!.destinationViewController() as DetailViewController
controller.name = name
}
The detail view controller can now populate its view with the passed information.