This question already has answers here:
Pass data through view controller, tab bar controller, navigation controller and to view controller
(2 answers)
Closed 8 years ago.
If a storyboard contains a view in a navigation controller that segues to another view controller already embedded in a tab controller how can a variable be passed from the initial view to the first view in a tab controller?
Specifically, I am looking to pass a variable using a basic performSegueWithIdentifier approach. By connecting the first view controller (embedded in a navigation controller) to the tab controller, I am unable to pass the data. However, if the connection is made directly between the first view controller and the destination view controller, the destination is no longer embedded in the tab.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "internalItemDetail" {
let destination = segue.destinationViewController as InternalInventoryDetail
let index = itemTable.indexPathForSelectedRow()!
destination.fmRecordId = sectionedItemArray[index.section][index.row]["fmRecordId"] as String!
}
}
To be clear, the goal is to pass a variable from a navigation controller into another view which is embedded in a tab controller while the UI would be showing a tab controller inside a navigation controller.
The UIStoryBoardSegue has a destinationViewController property that will give you the target view controller- in your case a UITabBarController (if I'm reading your question correctly). You'll have to cast it to a UITabBarController and from there you can access its subviews. (Code in objective c but should be easy to convert, I've just never used swift)
UITabBarController *tabControl = (UITabBarController *)segue.destinationViewController;
MyViewController *mv = (MyViewController *)tabControl.viewControllers[0];// whatever index you want
Related
I want to make an Flashcards App and the behaviour is that on the CoursesVC, the user can add courses and click on them. Then he gets the list with flashcards. There he can add more flashcards. The storage is managed by CoreData. When its clicked on the cell, I pass the data to the flashcards list with prepareForSegue. To add the flashcard, I had the same idea in mind, but it was not possible because the variable from the second view controller wasn't initialised, when prepareForSegue was created. Question: How can I pass a NSManagedObject from the first ViewController to the third ViewController in an appropriate way? (ugly way would be to let the view render before creating prepareForSegue)
The difference to questions like "how to pass data between ViewControllers" is that I have three ViewControllers. It won't work with using prepareForSegue at the first and at the second view controller, because when the prepareForSegue is created, the variable in the second VC is not defined yet, because the view is not initialised yet! Keep in mind that the segue from the second to the third view controller is "Present Modally" as "Page Sheet"!
This is the solution basically: Swift : prepareForSegue with navigation controller
The problem was that the third view controller is embedded as a navigation controller. That is the reason why the prepareForSegue is different.
Solution is to use following prepareForSegue in the second VC:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let navigationVC = segue.destination as? UINavigationController, let myViewController = navigationVC.topViewController as? DViewController {
myViewController.currentCourse = self.currentCourse
}
}
I'm trying to make a communication between tableview and it's detail view
Please can you check my way and give me some advices
So, I embedded Navigation Controller to Table view
and I didn't use tableview(_:didSelectedRowAt) method.
Some answers in Stackoverflow, they said override prepare(:) method and write theperformSegue(withIdentifier:) method in the tableview(_:didSelectedRowAt)
but if i write the code like above two screens were shown.
(I think because segue action are triggered twice)
I just drag and drop the segue action(push) to Detail View from table view cell (Friends Name Cell)
By using this segue action, i can pass the data by prepare(:segue) method for editing selected friend name at the Detail View
and if i edit friend name from detail view's text field, there is edit button which trigger the unwind segue
so I override prepare(:segue) method in Detail View Controller
and wrote code below at Table View's ViewController
#IBAction func getEditedNameFromDetailView(_ sender:UIStoryboardSegue){
if sender.source is DetailViewController {
if let senderVC = sender.source as? DetailViewController {
data[(self.someTableView.indexPathForSelectedRow?.row)!] = senderVC.editedData!
}
someTableView.reloadData()
}
}
is this a proper way to communicate table view and its detail view?
From your description it is possible that you have 2 segues. one in the StoryBoard and one in your code.
The prepare method is not performing the segue. it simply gives you a chance to perform actions that are related to the segue, for example pass data to the destinations controller. do not call perform segue if you already created one in the StoryBoard and vice versa.
a common usage of prepare will look like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//get the destination controller and cast it to your detail class
if let destinationController = segue.destination as? YourDetailClassHere {
//set the properties you want
destinationController.someProperty = someValue
}
}
Few notes -
you can use the sender object to pass data from the perform call.
common mistake is to assume that the destination controller is always your detail controller. it can be the navigation controller and then you will have to extract the detail from the navigation controller.
I would like to pass properties to a view controller created from a container view in a storyboard. The problem is that I don't know how I could do it.
The blue rectangle is the area where I have two containers view, each one referring to a view controller (one is the custom table view controller at the top and I am interested with and the other one to the view controller below).
The problem is that my custom table view controller needs some properties. I would like to pass the properties from the class where I instantiate the Storyboard (the storyboard is called from an toher class). The view controller containing the container views is instantiated like shown below:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Phenotype" bundle:nil];
GeneralViewController *vc = [sb instantiateViewControllerWithIdentifier:#"phenotype"];
[vc setProperty:property]; // I would like to pass this property to the custom table view controller.
[self.navigationController pushViewController:vc animated:YES];
I try to get the table view controller from the class where I instantiate the stroyboard to set the property at this time
TableViewController *tablevc = [sb instantiateViewControllerWithIdentifier:#"table"];
[tablevc setProperty:property];
...but without any success.
Would anyone have an idea how I can access the property from the custom table view controller directly from the view controller which is instantiating the storyboard?
Thanks for your help,
Select your embed segue from blue rectangle to the tableView on top and give it a segue identifier :) lets say segue identifier is "abcd".
In your ViewController having container write
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "abcd" {
let tableView : YourTableViewClass = segue.destination as! YourTableViewClass
//pass whatever params want :)
}
}
EDIT
Embedded segues behaves just like other segues with one exception that other segues you will have to execute them either programmatically or triggering some event where as embedded segue gets executed automatically when a container loads :)
So you can have segue identifier, write code in prepareForSegue just like you do it for other segues :)
I had a UINavigationController set as initial view controller. The root view controller for that navigation controller shows a menu where users can see product categories (In case that's interesting for anyone :)). The root view controller loads JSON data from an URL, so it takes a little while until the view shows up (which is fine). That data will be use in all the app, so it's an important step.
Well, since the data load takes a while, I added a new UIViewController where I show an image with an UIActivityIndicator. Of course, the data load takes place in this UIViewController now instead of the root view controller.
So, the idea is that after the data is loaded, the root view controller takes the place. To accomplish this I put an "invisible" UIButton on the new view controller and added a UIStoryboardSegue to the navigation controller, so I trigger that segue programmatically after the data is loaded.
After the data gets loaded, the navigation controller actually appears and shows (of course) the root view controller. The problem is when I click any button on the root view controller, the segue performs correctly, but from the "second" view controller (UITableViewController) if I press any cell, it takes me back to the new view controller (the one that shows an image and loads the data). Well not actually any cell, because sometimes it takes me actually forwards to the "third" view controller (also UITableViewController), but the same problem occurs in this view controller. If I click the back button on the navigation bar in any view controller, it takes me back to the new view controller and not really back in the navigation stack.
Here is ViewDidLoad:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
load.loadAllProducts()
load.loadCategories()
self.performSegueWithIdentifier("mainStoryboardSegue", sender: self)
}
And PrepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destination = segue.destinationViewController as? UINavigationController
let homeViewController = destination!.viewControllers.first as? HomeViewController
homeViewController!.categories = load.categories
homeViewController!.products = load.products
}
I really appreciate any help, thanks a lot!
The solution that worked for me was to change the current active view controller by setting this:
let newController = storyboard.instantiateViewControllerWithIdentifier(storyboardId) as? UINavigationController
UIApplication.sharedApplication().keyWindow!.rootViewController = newController
Im trying to get two navigation controller on the same stack, and pass data between them , the best way to explain this is by the image below .
first nav controller(the one thats furthest to the left ) is connected to a TabBarController .
When passing data from the TEST tableViewController to the 2nd tableViewController (subDuaList) , i get an error in my code in the prepareForSegue method ...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var subDua:subDuaList = segue.destinationViewController as subDuaList //ERROR OCCURS HERE
var Index = tableView!.indexPathForSelectedRow()?.row
var duaIndex = 130 - Index!
var selectedDua = self.packagedChapter[duaIndex]
println(selectedDua.title)
subDua.duaArray = selectedDua.dataArray
subDua.rowPressed = Index
}
Reason for embedding the second tableViewController in a Navigation controller is so that I can add a bar button item to the nav bar.
EDIT
As #Shim commented right, my answer just explains the reason for the error output, but does not tell the things I already said in my comment on your question:
It is not allowed to push a UINavigationController on an existing navigation stack. Therefore you should remove the second navigation controller and just add a UIBarButtonItem to the navigationItem of your subDuaList view controller.
The reason for your error is, that the segue.destinationViewController is the second UINavigationController and not the subDuaList view controller.
If it was allowed, you could have repaired your code as follows by replacing:
var subDua:subDuaList = segue.destinationViewController as subDuaList //ERROR OCCURS HERE
with
var navCtrl:UINavigationController = segue.destinationViewController as UINavigationController
var subDua:subDuaList = navCtrl.childViewControllers[0] as subDuaList
You don't need a new navigation controller to add a bar button item. You can add a bar button item in the storyboard by dragging it onto the navigation bar (if the view controller is in a navigation stack and you don't see one, check the simulated metrics in the inspector), or you can add it in code like so:
self.navigationItem.rightBarButtonItem = myBarButtonItem;