Perform a parent segue from the embedded view controller - ios

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

Related

viewDidLoad() of segue.destinationViewController called twice before prepareForSegue()

So what I'm trying to do is to send an object from a tableViewController to a collectionViewController via the sender parameter of the prepareForSegue method in didSelectRowAtIndexPath but for some reason the viewDidLoad method of that collectionViewController is being called twice before prepareForSegue. Here's the relevant code from the tableViewController:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let challenge = dataModel.challenges[indexPath.row]
performSegueWithIdentifier("ShowChallengeSegue", sender: challenge)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
...
else if segue.identifier == "ShowChallengeSegue" {
let controller = segue.destinationViewController as! ChallengeViewController
controller.challenge = sender as! Challenge
}
}
After adding a bunch of print statements the following is happening in sequence:
tableViewController's didSelectRowAtIndexPath is called
destinationViewController's (collectionViewController) viewDidLoad is called
destinationViewController's (collectionViewController) viewDidLoad is called again
tableViewController's prepareForSegue is called
I have no idea why is this happening, would appreciate any help.
Edit - I replaced the collectionViewController with a tableViewController and everything seems be working fine so it might be something related specifically to UICollectionViewController.
you must have took segue from cell instead of whole controller so that segue is performed twice
Please take segue from Controller then try
OR
add this code
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
return false;
}
#Gerwazy Sokołowski
Check your xib file in storyboard. i think you linked segue from button or any other view. segue should be set with UIViewcontroller then you can call performSegueWithIdentifier

Pass Data from UICollectionView in Swift 2

My problem is I would like to Pass data from my collection view to a new view (tableview- but I think it's not necessary info)
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = DetailsTableViewController()
myVC.movieTitle = movies[indexPath.row].movieTitle!
print (movies[indexPath.row].movieTitle!)
performSegueWithIdentifier("DetailSegue", sender: reuseIdentifier)
}
Print is OK, but my movieTitle: String? will NIL on the DetailsViewController.
Help!
performSegueWithIdentifier will instantiate an appropriate destination controller and present it. The DetailsTableViewController you have instantiated here as myVC is never shown. You have a couple of options for how to approach this:
If you want to use segues then trigger the segue in didSelectItemAtIndexPath and implement prepareForSegue to pass data to the destination view controller (a destinationViewController will be available on the UIStoryboardSegue passed to that method).
Alternately you could avoid using segues and present your myVC directly by pushing it onto your current navigation controller (if one exists you could call self.navigationController.pushViewController(myVC, animated:true)), presenting it as a modal, or whatever makes sense in your app.
problem solved. thanks
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DetailSegue" {
let detailsVC = segue.destinationViewController as! DetailsTableViewController
if let cell = sender as? UICollectionViewCell, indexPath = collectionView!.indexPathForCell(cell) {
// use indexPath
detailsVC.movieTitle = movies[indexPath.row].movieTitle!
}
}
}

segue from UIViewController to UITableViewController

I'm trying to segue data from UIViewController to UITableViewController.
The data in UIViewController is coming from PFTableViewController and I want to pass that data to another TableViewController.
For passing to ViewController didSelect method is used but I have no idea how can I segue from viewController to TableViewController.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let destinationToFVC:ViewController = self.storyboard!.instantiateViewControllerWithIdentifier("FVCont") as! ViewController
if let indexPath = self.tableView.indexPathForSelectedRow {
let row1 = Int(indexPath.row)
destinationToFVC.currentObject = objects?[row1] as! PFObject!
}
navigationController?.pushViewController(destinationToFVC, animated: true)
}
I'm new to programming.
In your case you can launch the segue manually from your didSelectRowAtIndexPath, with the the method performSegueWithIdentifier.
You need to create a custom segue in your Storyboard from your UIViewController to your UITableViewController and set an Identifier for it, you can press Ctrl + Click from your UIViewController to the next to create the custom segue and then select the segue and in the Attributes Inspector set the Identifier for the segue just a this picture:
Then you can in your didSelectRowAtIndexPath launch the segue manually as in this code:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// the identifier of the segue is the same you set in the Attributes Inspector
self.performSegueWithIdentifier("mySegueID", sender: self)
}
And of course you need to implement the method prepareForSegue to pass the data from your UIViewController to your UITableView like in this code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "mySegueID") {
// in this line you need to set the name of the class of your `UITableViewController`
let viewController = segue.destinationViewController as UITableViewController
let indexPath = self.tableView.indexPathForSelectedRow()
destinationToFVC.currentObject = objects?[indexPath] as! PFObject!
}
}
EDIT:
If you want to perform your segue from an UIButton to the UITableViewController it's the same logic, just create the custom segue in your Storyboard and then call the prepareForSegue like in the following code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "mySegueID") {
// in this line you need to set the name of the class of your `UITableViewController`
let viewController = segue.destinationViewController as UITableViewController
/ here you need to pass the data using the reference viewController
}
}
I hope this help you.

Its possible to change font of UILabel from other ViewController class

I have a ViewController which consist of UILabel and UIButton. OnClick UIButton a popOver present which show tableView. each cell of tableView represent different font option.
I want to change the font of UILabel based on user selected font from tableViewCell. how i can achieve this as my UILabel and tableView are in different viewController class.
Please help me.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var row = indexPath.row
// How to update label from here
}
Edit : I fond this answer but not able to understand as its return in objective c update ViewController label text from different view
You can use delegate. In your popover Swift file create such protocol:
protocol PopoverDelegate {
func didSelectFont(font: UIFont)
}
In your popover class create such implementation of newly created protocol:
class popoverviewcontroller : UITableViewController {
var delegate: PopoverDelegate?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var row = indexPath.row
// How to update label from here
delegate.didSelectFont(youFontHere)
}
}
Now in your main view controller, if you are presenting your popover programmatically, you should set your popover's delegate property to self. If your are presenting popover from storyboard, just handle segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
let destination = segue.destinationViewController as! popoverviewcontroller
destination.delegate = self
}
Now implement delegate method:
func didSelectFont(font: UIFont) {
//Update label's font
}
And of course don't forget to add delegate to your main view controller:
class mainViewController: UIViewController, PopoverDelegate { ...
Hope it helps!

Swift: Make button trigger segue to new scene

Alright, so I have a TableView scene and I'm going to put a button in each of the cells and I need each cell to, when clicked, segue to its own ViewController scene. In other words, I need to know how to connect a button to a scene (The only button I have right now is "milk")
I know how to create an IBAction linked to a button, but what would I put in the IBAction?
I'm a beginner so I need a step-by-step explanation here. I've included a picture of my storyboard. I haven't written any code yet.
If you want to have a button trigger the segue transition, the easiest thing to do is Control+Click from the button to the view controller and choose a Segue option (like push). This will wire it up in IB for you.
If you want to write the code to do this yourself manually, you can do so by naming the segue (there's an identifier option which you can set once you've created it - you still need to create the segue in IB before you can do it) and then you can trigger it with this code:
V2
#IBAction func about(sender: AnyObject) {
performSegueWithIdentifier("about", sender: sender)
}
V3
#IBAction func about(_ sender: Any) {
performSegue(withIdentifier: "about", sender: sender)
}
You can use the delegation pattern. Presuming that you have implemented a custom table cell, you can define a property in its class to hold whatever you think is helpful to identify the row - it can be its index, or (my preferred way) an instance of a class which represents the data displayed in the cell (I'm calling it MyCellData.
The idea is to let the cell notify the table view controller about a tap on that button, passing relevant data about (the data displayed in) the row. The table view controller then launches a segue, and in the overridden prepareForSegue method it stores the data passed by the cell to the destination controller. This way if you have to display details data about the row, you have all the relevant info, such as the details data itself, or an identifier the destination view controller can use to retrieve the data for example from a local database or a remote service.
Define a protocol:
protocol MyCellDelegate {
func didTapMilk(data: MyCellData)
}
then declare a property named delegate in the cell class, and call its didTapMilk method from the IBAction
class MyTableCell : UITableViewCell {
var delegate: MyCellDelegate?
var data: MyCellData!
#IBAction func didTapMilk() {
if let delegate = self.delegate {
delegate.didTapMilk(self.data)
}
}
}
Next, implement the protocol in your table view controller, along with an override of prepareForSegue
extension MyTableViewController : MyCellDelegate {
func didTapMilk(data: MyCellData) {
performSegueWithIdentifier("mySegueId", sender: data)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "mySegueId" {
let vc: MyDestinationViewController = segue.destinationViewController as MyDestinationViewController
vc.data = sender as? MyCellData
}
}
}
Of course you need a data property on your destination view controller for that to work. As mentioned above, if what it does is displaying details about the row, you can embed all required data into your MyCellData class - or at least what you need to retrieve the data from any source (such as a local DB, a remote service, etc.).
Last, in cellForRowAtIndexPath, store the data in the cell and set its delegate property to self:
extension MyTableViewController : UITableViewDataSource {
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let data: MyCellData = retrieveDataForCell(indexPath.row) // Retrieve the data to pass to the cell
let cell = self.tableView.dequeueReusableCellWithIdentifier("myCellIdentifier") as MyTableCell
cell.data = data
cell.delegate = self
// ... other initializations
return cell
}
}
Use self.performSegueWithIdentifier("yourViewSegue", sender: sender) under your event for handling button's click:
#IBAction func redButtonClicked(sender: AnyObject) {
self.performSegueWithIdentifier("redView", sender: sender)
}
In the above code, redView is the segue identifier.

Resources