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

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

Related

Xcode: Passing Information from UITableViewController to UIViewController

I have a UIViewController which should show me DetailInformations depending on what Cell was pressed in the UITableViewController.
For the moment I am passing them through a sequel:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "show" {
var ctrl = segue.destination as! DetailViewController
ctrl.information = _informationList[id]
}
}
The id variable is set through:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
id = indexPath.row
}
Now in my UIViewController I change the information with:
override func viewDidLoad() {
super.viewDidLoad()
setInformation(i: information)
}
Now my problem is, that if I press, lets say cell 2. It switches to the ViewController and shows Information of cell 1. Than I go back to the tableview and I press cell 3. Then it shows me cell 2.
In short, it seems that the viewController is loaded (with the last information), before it sets the new information.
Is there any better way to solve this?
Try using indexPathForSelectedRow in prepareForSegue as of it looks like that you have created segue from UITableViewCell to the Destination ViewController so that prepareForSegue will call before the didSelectRowAt.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "show" {
var ctrl = segue.destination as! DetailViewController
if let indexPath = self.tableView.indexPathForSelectedRow {
ctrl.information = _informationList[indexPath.row]
}
}
}
I am assuming based on what you are describing is that you used a segue in your Storyboard to link directly from the cell to the detail view controller. This is not what you want to do, as mentioned earlier, because you don't get the order of events you would expect. You could use the delegation design pattern for this, but assuming you want to stick with segues you need to make the "show" segue from the table VC itself to the detail VC. You then manually call the segue from the tableView didSelectRowAt code.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
id = indexPath.row
performSegue(withIdentifier: "show", sender: self)
}
Finally, you could then use an unwind segue when you come back to catch any data changes initiated in the detail VC.

How to pass selected row data to another ViewController

I have a tableview like this
I want to take the link and pass it to another controlview.
Here what i have done
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let linktopass = classes[indexPath.row].valueForKey("link")
print(linktopass)
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let thirdVC: web = segue.destinationViewController as! web
thirdVC.link = linktopass as! String
But it does not work.
Here is my print's output.
Optional( http://blablabla )
If think you forget to performsegue in didSelectRowAtIndexPath.
prepareForSegue is get called before you performsegue. if you are not performing segue then your prepareForSegue will not called.
so, in didSelectRowAtIndexPath, add code like,
performSegueWithIdentifier("goToNextVC", sender: self) //your segue identifier here
//goToNextVC is segue identifier set from attribute inspector from storyboard
Make sure you have set segue identifier from attribute inspector.
You can set identifier like,
select segue - click attribute inspector - write identifier in it - press enter
Hope this will help :)

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.

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

Resources