Show ViewController from XIB-file-Button - Swift - swift

is there a way how to segue from a xib-file (custom TableViewCell) to another ViewController in the Main.storyboard.
There's no possibility to drag a segue, like within the main storyboard.
In the cell I've got a button, from where I want to change the view.
How can I solve it?
Thanks!

You can always instantiate a view controller from your Storyboard and present it on button tapped:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("ViewControllerID") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)

Define a segue in StoryBoard and specify the identifier, like detail
Perform segue in talbeView(_, didSelectRowAtIndexPath):
Use self.performSegueWithIdentifier to fire a segue
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("detail", sender: nil)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

Related

Xcode Cannot go back to TableViewController in navigation stack

I have controller1 -> TableViewController2 -> TableViewController3 in my storyboard. When I press a button in controller1, I want to jump to TableViewController3 and from there when I select a row, I want to go back to TableViewController2 and get some data and then go back to controller1.
In controller1 instantiate TableViewController3:
if segue.identifier == "MySegue" {
let viewController:TableViewController3 = segue.destination as! TableViewController3
viewController.addLocationToMap = true
}
In TableViewController3 instantiate TableViewController2 like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if addLocationToMap == true {
let navc:UINavigationController = self.navigationController!
let tvc:UITableViewController = TableViewController2()
let rootView = navc.viewControllers[0]
navc.setViewControllers([rootView, tvc], animated: true)
return
}
In TableViewController2 viewDidLoad, it fails in ViewDidLoad when I try to set a text field value because the textfield is nil. It cannot be because Textfield is already in the view. Looks like the TableViewController2 view never got loaded.
in TableViewController2
override func viewDidLoad() {
super.viewDidLoad()
locationPurposeTextField.text = "sometext"
}
Fails when setting text value because locationPurposeTextField is nil.
How to fix this?
EDITS:
On pressing a button In controller1:
let navc:UINavigationController = self.navigationController!
let alTvc = self.storyboard!.instantiateViewController(withIdentifier: "AddLocationID") as! UITableViewController
navc.pushViewController(alTvc, animated: false)
let cListTvc = self.storyboard!.instantiateViewController(withIdentifier: "ContactListID") as! UITableViewController
navc.pushViewController(cListTvc, animated: true)
The code takes me to TableViewController3 with storyboard ID: ContactListID as desired.
Next, in TableViewController3
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.myDelegate?.userSelectedContact(contactIdentifier: self.contactId, contactFullName: fullName, contactSelected: true)
let navc:UINavigationController = self.navigationController!
let tvc:UITableViewController = self.storyboard!.instantiateViewController(withIdentifier: "AddLocationID") as! UITableViewController
let rootView = navc.viewControllers[0]
navc.setViewControllers([rootView, tvc], animated: true)
}
Takes me to TableViewController2 with storyboard ID: AddLocationID
Based on the delegate sent TableViewController3, in ViewDidappear method of TableViewController2, I set some text in the view and call tableview.realoadData(). It does not load the view.
However if I select a button in TableViewController2 and load TableViewController3 and then comeback to TableViewController2 upon execution of the very same method didSelectRow it reloads the view in TableViewController2
How to fix it, please let me know?
There are a couple of things wrong with your approach.
If you want to go from controller1 to TableViewController3 but have your navigation stack contain controller1 -> TableViewController2 -> TableViewController3, you will have to have the button in controller1 first push TableViewController2 without animation, and then push TableViewController3 with animation. (You won't be able to have your button trigger a segue.)
Second problem: You can't create a copy of your TableViewController2 by just invoking it's initializer (TableViewController2()). When you do that it doesn't load its views from the storyboard. Instead, you should assign a storyboard identifier to it and use the UIStoryboard method instantiateViewController(withIdentifier:) to create a new instance of it.

Perform a segue programmatically

Hi I'm trying to perform a segue programmatically without the Storyboard. Currently I have this as my code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popOutNoteExpanded" {
let vc = segue.destination as! ExpandedCellViewController
let cell = sender as! AnnotatedPhotoCell
sourceCell = cell
vc.picture = cell.imageView.image
print("button pressed")
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
performSegue(withIdentifier: "popOutNoteExpanded", sender: indexPath)
}
When I click on the collection view cell it's saying that:
has no segue with identifier 'popOutNoteExpanded'.
Not sure how to perform my custom animated transition.
To trigger a segue programmatically, you have to follow steps:
1. Set it up in Storyboard by dragging your desired segue between two view controllers and set its identifier (for example, in your case is "popOutNoteExpanded") in Attributes Inspector section.
2. Call it programmatically
performSegue(withIdentifier: "popOutNoteExpanded", sender: cell)
Please check if you set its identifier correctly or not.
Besides, in your above code, you put an incorrect sender.
In your prepare() method, you use the sender as a UITableViewCell, but you call performSegue() with sender as a IndexPath.
You need a cell by calling:
let cell = tableView.cellForRow(at: indexPath)
And then you can perform a segue:
performSegue(withIdentifier: "popOutNoteExpanded", sender: cell)
Segues are components of storyboard. If you don't have a storyboard, you can't perform segues. But you can use present view controller like this:
let vc = ViewController() //your view controller
self.present(vc, animated: true, completion: nil)
Additional to the correct answer, please be aware that if you are in a navigation stack (say, you are in a Settings page and want to segue to an MyAccountVC) you should use:
let vc = MyAccountVC()
self.navigationController?.pushViewController(vc, animated: true)
If the navigated VC appears with a transparent background during the transition, just set the backgoundColor of it to .white.
In my case I was presenting a TableViewController, without a segue defined, and found it was necessary to instantiate from the storyboard otherwise tableViewCells couldn't be dequeued in cellForRowAt.
let vc = (storyboard.instantiateViewController(withIdentifier: "YourTableViewController") as? YourTableViewController)!
self.navigationController!.pushViewController( vc, animated: true)

Dynamic TableView Cell to Multiple Detail Views Swift

I'm using presentViewController to navigate between two views in XCode. I was wondering how I might select a cell row from a dynamic tableView to navigate to a view controller. So, basically, when I tap a dynamic cell, each cell navigates to its own different view. How might I do this?
So far I have this code:
#IBAction func press(sender: AnyObject) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: UINavigationController = storyboard.instantiateViewControllerWithIdentifier("newViewController") as! UINavigationController
self.presentViewController(vc, animated: true, completion: nil)
}
But, instead of using a button, I would like each cell to lead to another particular view as I said above.
thanks in advance
Create an array that holds the view controller identifiers:
let identifiers = ["newViewController", "newViewController2", "newViewController3"]
Implement this UITableViewDelegate method in your view controller:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let identifier = identifiers[indexPath.row] {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: UINavigationController = storyboard.instantiateViewControllerWithIdentifier("newViewController") as! UINavigationController
self.presentViewController(vc, animated: true, completion: nil)
}
}
Don't forget to set your tableView's delegate to the view controller that contains the tableview and that implements the above delegate method.

Table View To Custom View Controller?

I Wanted to know if I have two cells in a tableview, and I want that if i click the first cell it seagues to specific view controller, and if I click the second cell it seagues to another view controller.
How can I do that?
You can do it this way in didSelectRowAtIndexPath method:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
switch indexPath.row {
case 0 :
println("First cell")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
case 1 :
println("Second Cell")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
default:
println("No cell selectd")
}
}
HERE is your sample project.
Call performSegue:withIdentifier: from the method didSelectRowAtIndexPath in your view controller. You can conditionally call segues with different identifiers in your code.

Master-Detail: UINavigatorController vs Storyboard Segue

Scenario: Master(TableView) --> Detail.
Modus Operandi: Select Row --> display DetailVC
As you can see below, I have a MasterVC embedded in a UINavigationController:
I currently display the DetailVC via pushing it into the UINavigationController's VC stack:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("tableView didSelectRowAtIndexPath")
let storyboard = UIStoryboard(name: "Bliss", bundle: nil);
let controller = storyboard.instantiateViewControllerWithIdentifier("DiaryPlayerVC") as DiaryPlayerViewController
self.navigationController?.pushViewController(controller, animated: true)
}
This works fine.
However, the 'prepareForSeque' doesn't fire:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDiaryPlayer" {
if let indexPath = self.tableView.indexPathForSelectedRow() {
let object = objects[indexPath.row] as NSDate
// (segue.destinationViewController as DiaryPlayerViewController).detailItem = object
}
}
}
I understand that I probably have two (2) conflicting paradigms here:
1) Using the UINavigationController vs
2) Using the Storyboard Relationship.
So...
Option 1: it appears that I can remove the Segue link to have a storyboard stand-alone DetailVC.
Option 2: via Segue, I'm assuming I can remove the UINavigatorController from the link.
I'm currently using Option #1, launching the DetailVC via the UINavigationController.
Question: If I choose Option #2, how do I access (launch) the DetailVC ("Diary Player") from the Master's Row and hence, fire the Segue's 'prepareForSegue()'?
Answer: create a segue from the table view cell to the detail view controller.
Your screenshot shows that you already created a segue in your storyboard. Give that segue an identifier in its property inspectory. Then you can simply perform the segue in the didSelectRowAtIndexPath method:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("tableView didSelectRowAtIndexPath")
performSegueWithIdentifier("mySegueIdentifier", sender: nil)
}
Note: Ctrl-drag the segue from the TableViewController icon, not from the TableViewCell.