Navigating different table-cell to different UIVewController in Swift - ios

I am sorry for echoing same question but after a lot of time spending I could not figure out the issue.
Suppose, a UITableView have 2 table_cell s and I want to navigate different UIViewController from each table_cell. How do I do that?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
// go to DetailVC_1
} else if indexPath.row == 1 {
// go to DetailVC_2
}

Either present a new view controller manually:
self.presentViewController(controller, animated:true, completion:nil)
// or push on a navigation controller
self.navigationController.pushViewController(controller, animated:true)
Or perform a segue you set up in a storyboard earlier. (Drag from the view controller to another view controller in your storyboard).
self.performSegueWithIdentifier("MyIdentifier", sender: self)
When using storyboards you can also use multiple cell types and setup a segue from each cell type to a new controller. This way the new controller will be presented automatically. The only code you might need to use in that case would be a prepareForSegue method where you pass the correct information to the presented controller before the segue is performed.

Try this:
if indexPath.row == 0 {
self.performSegueWithIdentifier("firstViewController", sender: self)
} else if indexPath.row == 1 {
self.performSegueWithIdentifier("secondViewController", sender: self)
}
If you have several view controllers, you can call them viewController0 and viewController1 etc. Then you can have a string "viewController" + String(indexPath.row). Hope this helps.

Related

Swift - How to implement a defaultviewcontroller loop

I'm attempting to create 2 different default view controllers that then get called and do their specified action depending on what was in the cell. Would you create the view controller in the main storyboard use an xib, etc?
Basically I have a xml file that I'm parsing and then creating table views for till I get to the last (details) page for the item. From my understanding it is better to use the same tableviewcontroller multiple times instead of creating 1 for each level. Am I supposed to be creating a segue loop?
There are checks currently in place to make sure I use the right segue.
Would you pefrom the segue with:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath as IndexPath)
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
segueLocation = hNTUL[(indexPath as NSIndexPath).row].locationLevel
segueTitle = hNTUL[(indexPath as NSIndexPath).row].locationTitle
if segueLocation == "TableView" {
performSegue(withIdentifier: "defaultDetailSeague", sender: cell)
let destinationVC = DefaultDetailViewController()
destinationVC.detailTitle = segueTitle
}
if segueLocation == "DetailView" {
performSegue(withIdentifier: "defaultTableSeague", sender: cell)
let destinationVC = DefaultTableViewController()
destinationVC.tableTitle = segueTitle
}
}
It is also possible that I'm trying to go about this the wrong way.
I've also been searching for project examples but haven't found any that might guide me in the right direction.
Thoughts?
If you call performSegue, you must not create a destinationVC; the segue creates it for you. To configure the destination view controller, implement prepare(for:sender:) and fetch the segue's destination, casting it down to a DefaultDetailViewController. Be sure to check that this is the right segue first!

How to run a segue on itself OR another viewController

I have a main TableViewController. When the user tap on a cell in TableView, If a condition statement is true, show the main TableViewController again(but show another data on screen), and if the condition is false, show another ViewController.
In the prepareForSegue method I have this:
if segue.identifier == "identifier1"
{
let destination = segue.destinationViewController as? mainViewController // itself
destination!.x = something // the x variable is in this view controller
}
else if segue.identifier == "identifier2"
{
let destination = segue.destinationViewController as? viewController2
destination!.y = something
}
Also, to run segue after tap on cells in tableView I added this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if condition is true {
self.performSegueWithIdentifier("identifier1", sender: self)
}
else{
self.performSegueWithIdentifier("identifier2", sender: self)
}
}
Storyboard segue needs an identifier... It can just have one value! identifier1 or identifier2
But I want to set the identifier programmatically.
How should I set the identifier in Storyboard segue?
Is there another way to do this?
Thanks!
The destination view controller is set by the segue. Since you have two different destinations, you need two different segues in your Storyboard.
The trick is to wire the segues from the viewController icon at the top of tableViewController to each of the destination view controllers. Click on the resulting segue arrows and set their identifiers in the Attributes Inspector.
Then you can call them with performSegueWithIdentifier as you have done in your code.
Don't invoke a segue directly from the cell tap. Use an IBAction method (probably in `didSelectRowAtIndexPath, like you show in the second block of code.
That second block of code DOES set the segue identifier programmatically.
You can't switch segues in prepareForSegue.

Navigation like in the mail app with segues and dynamic cells in a table view?

I'm currently developing my first iOS app for a college. When you start the app, there is a grouped table view which should represent a menu. This works fine so far, but I'm unable to connect the segues properly. As far as I know I should connect the cell itself with the navigation controller it should lead to. Although every cell should lead to another navigation controller. It's a menu, so that point should be clear. Unfortunately I'm unable to connect a single cell with multiple navigation controllers and when I add multiple prototype cells, I have the problem that every cell should have it's own identifier.
The first screen you see in my app looks basically like the mail app. There are two groups and each cell leads to another navigation controller.
I managed to implement the navigation in some weird way, but get a lot of bugs like "nested push results in corrupted nav bar".
I'm absolutely frustrated right now, I spent a lot of hours on this single problem already and I'm unable to find any solution.
edit:
one of the biggest problems currently is that if I navigate to a point and then head back the the view before, the grouped view is first displayed too close to the top and when the animation is complete the whole view jumps back down where it belongs.
this is how it should look like (and looks like when it jumps back): https://dl.dropboxusercontent.com/u/34140308/uploads/2016-04-25%2010.28.48.png
this is how it looks like during the animation: https://dl.dropboxusercontent.com/u/34140308/uploads/2016-04-25%2010.28.48%202.png
edit2: I connected the view controller itself (not the cells) with the respective view controller. Then I call the segues programmatically like this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if indexPath.section == 0 {
if indexPath.row == 0 {
self.performSegueWithIdentifier("showSpeiseplan", sender: self)
} else if indexPath.row == 1 {
self.performSegueWithIdentifier("showStudiersaal", sender: self)
} else if indexPath.row == 2 {
self.performSegueWithIdentifier("showErzieher", sender: self)
} else if indexPath.row == 3 {
self.performSegueWithIdentifier("showHausordnung", sender: self)
} else if indexPath.row == 4 {
self.performSegueWithIdentifier("showNews", sender: self)
}
} else if indexPath.section == 1 {
if indexPath.row == 0 {
self.performSegueWithIdentifier("showZugewieseneStunden", sender: self)
}
}
}
The other major problem right now is that if you press a single cell multiple times before it's loaded, the view gets opened multiple times as well.
The way I usually do segue's from a tableView is by connecting the segue from the viewController rather than the tableviewCells. This way you can call performSegueWithIdentifier in didSelectRowAtIndexPath.
Eg
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
tableView.userInteractionEnabled = false
switch indexPath.section {
case 0:
switch indexPath.row {
case 0: performSegueWithIdentifier("showSpeiseplan", sender: self)
case 1: performSegueWithIdentifier("showStudiersaal", sender self)
case 2: performSegueWithIdentifier("showErzieher", sender self)
case 3: performSegueWithIdentifier("showHausordnung", sender self)
case 4: performSegueWithIdentifier("showNews", sender self)
default: tableView.userInteractionEnabled = true
}
case 1:
switch indexPath.row {
case 0: performSegueWithIdentifier("showZugewieseneStunden", sender: self)
default: tableView.userInteractionEnabled = true
}
default: tableView.userInteractionEnabled = true
}
}
and in viewWillDisappear:
override func viewDidDisappear(animated: Bool) {
tableView.userInteractionEnabled = true
}
If your cells are editable or dynamic (they change indexPath) then either use cell.tag in cellForRowAtIndexPath to distinguish them, or add a property to you custom cell class (or make one if you haven't) and add a property that you can use to identify the correct segue.
Edit: To fix the tableView Offset jump on animation, create a variable tableViewContentOffset above viewDidLoad, and then in viewDidLoad add:
tableViewContentOffset = tableView.contentOffset
and in viewWillAppear restore it if it has changed.
if tableView.contentOffset != tableViewContentOffset {
tableView.contentOffset = tableViewContentOffset
}
also, maybe just see what happens when you put this in viewWillAppear:
tableView.contentOffset = CGPointZero
tableView.contentInset = UIEdgeInsetsZero

Perform a parent segue from the embedded view controller

I have this:
MyTableViewController (inherits from UITableViewController)
It has a dynamic tableview with a few cells (foo, bar, qux)
MyViewController (inherits from UIViewController)
There are some "show" segues from this controller to other view controllers
It has a UIContainerView that embeds MyTableViewController
A picture speaks a thousand words:
When a certain cell is selected, I want to perform a segue of the parent view (MyViewController)
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (indexPath.section == 1 && indexPath.row == 1) {
self.WHAT.performSegueWithIdentifier("someShowSegue1", sender: self)
}
}
Is it possible? what should I use in «WHAT»?
In the prepareForSegue: for your embedded segue set the viewController in a new property in your tableViewController, let's name it parentController. And then you'll have just to call self.parentController.performSegueWithIdentifier().
EDIT: But first of all, maybe you can use the existing parentViewController if it contains the embedding view controller.
You may want to consider using delegation to solve this problem since the child tableView doesn't seem like it should be responsible for the segue. For example:
// MyViewController
class MyViewController: UIViewController, MyTableViewControllerDelegate {
func selectedMyTableViewControllerCell(cell: UITableViewCell) {
// ... check cell type or index or whatever
self.performSegueWithIdentifier("someValueFromCellType", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == myTableViewControllerIdentifier {
if let vc = segue.destinationViewController as MyTableViewController? {
vc.delegate = self
}
}
}
}
// MyTableViewController
protocol MyTableViewControllerDelegate: class {
func selectedMyTableViewControllerCell(cell: UITableViewCell)
}
class MyTableViewController: UITableViewController {
weak var delegate: MyTableViewControllerDelegate?
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// ... get the cell
delegate?.selectedMyTableViewControllerCell(cell)
}
}
No need to create a property. Just this
self.parent?.performSegue(withIdentifier: "ID", sender: self)
SWIFT 4
Swift 4 no longer has parentViewController. You must use parent to access the parent object and is an optional so be sure to check for nil where necessary.
self.parent?.performSegue(withIdentifier: "IdentifierHere", sender: self)
Hook your segue up to the embedded table view controller's cell instead. You can use different segues per cell prototype. This saves you from checking index paths or even implementing didSelectRow at all.
Segue is defined from one view controller to another and is only invoke from the view controller in which it is defined. So you would need to store the reference of the parentViewController.
Like from MyViewController
if ([segueName isEqualToString: #"embedseg"]) {
MyTableViewController * tblViewController = (MyTableViewController *) [segue destinationViewController];
tblViewController.parentController=self; //Storing reference of parentViewController i.e MyViewController
}
Now you can simply invoke segues like
self.parentController.performSegueWithIdentifier("someShowSegue1", sender: self)
Hope this helps

Load discrete view from table view?

So I have a table view that I want to segue to specific views when a specific cell is selected. For example, if the cell at index 0 is selected, I want the "RedViewController" to be visible.
The example I keep receiving looks something like this (located in the VC with the table view)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let destination = segue.destinationViewController as? RedViewController {
if let blogIndex = tableView.indexPathForSelectedRow()?.row {
destination.blogName = swiftBlogs[blogIndex]
}
}
}
}
(Where blogName and swiftBlogs are random examples)
But this just loads specific data into a singular view controller. Preferably I want a switch statement for each index path that makes a specific VC visible.
Ok, so write your code that way. Don't link your table views directly with a segue. Instead write code in your didSelectRowAtIndexPath.
In that method you can write a switch statement, or use an array lookup, to load a view controller using a unique ID and the instantiateViewControllerWithIdentifier, or trigger a through code using performSegueWithIdentifier.
I figured it out thanks to Duncan C and a little more research!
In the table view VC I added the handy function
func switchToViewController(identifier: String) {
let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(identifier) as! UIViewController
self.navigationController?.setViewControllers([viewController], animated: false)
}
And in the didselectRowAtIndexPath
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedRow = indexPath.indexAtPosition(indexPath.row)
switch selectedRow {
case 0:
switchToViewController("RedVCIdentifier")
default:
println("Unknown Cell selected")
}
}
But also had to add a Storyboard ID to the RedViewController in the storyboard as "RedVCIdentifier"

Resources