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 :)
Related
I have a Navigation controller embedded to a VC called UserDashboardVC. I then have a menu VC and the one option opens another VC with a tableview, ManageAccountVC. When I select the table row I would like it to unwind and populate the data on the UserDashboardVC.
I'm struggling to pass the data back to the UserDashboardVC using unwind segue from ManageAccountVC.
In my UserDashboardVC (root) I have my unwind segue code:
#IBAction func unwindUserDashboardVC(_ unwindSegue: UIStoryboardSegue) {
userCompanyLabel.text = PassCompanyOffice}
In my ManageAccountVC the tableview cell has been connected to Exit unwindUserDashboardVC, this works, when I click on the cell I unwind to UserDashboardVC. I have a function in ManageAccountVC to get the row selected:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
PassCompanyOffice = userAccountArray[indexPath.row].companyOffice!
}
I also have the Prepare function in ManageAccountVC which seems to trigger before I get my row value:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let ConfirmVC = segue.destination as! UserDashboardVC
ConfirmVC.PassCompanyOffice = PassCompanyOffice
}
Why is my unwind segue being performed before my cell row is identified? How do I pass back my data?
You may want to create a class member to hold the selected row and assign that in willSelectRow for the tableview. Then pickup the value in the prepare for Segue or the unwind segue in this case. Put a breakpoint in the unwind segue to determine the state of the selected row variable before using it.
Manual Segue
To separate the cell click action from the segue you will need to remove the exit segue that you made from the tableview cell to the exit.
Then create a manual segue from the view controller to the exit icon. Give that segue an identifier and then call the performSegue with identifier (using the exitSegueIdentifier)
This way you separate the two actions. You can click on the table without exiting. In your code base you can decide when you want to call the performSegue and actually close the VC using the manual exit segue.
As #Tommie C. mentioned, my issue was with the TableViewCell that was linked to the Storyboard Exit. I removed that segue and added a manual Exit seguel by doing this:
Make sure the above is made identifiable, in this case it is "loadDashboardSegue". The Prepare function has the segue identifier name "loadDashboardSegue":
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "loadDashboardSegue" {
let ConfirmVC = segue.destination as! UserDashboardVC
ConfirmVC.PassCompanyOffice = PassCompanyOffice
}
}
Lastly, you action the segue manually in the tableview row select:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
PassCompanyOffice = userAccountArray[indexPath.row].companyOffice
performSegue(withIdentifier:"loadDashboardSegue", sender: self)
}
I tried to pass the value of the cell that the user clicks on to another view controller.
Here is my code.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
productDisplayed = currentProductList[indexPath.row] as? Product
performSegue(withIdentifier: "ProductDetailSegue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if ( segue.identifier == "AddProductSegue"){
let controller: AddProductViewController = segue.destination as! AddProductViewController
controller.delegate = self
}
if ( segue.identifier == "ProductDetailSegue"){
let controller: ProductDetailsViewController = segue.destination as! ProductDetailsViewController
controller.currentProduct = productDisplayed
}
}
Firstly, I didn’t write “performSegue()”.
The issue I met is that the screen will be transferred firstly rather than assign the value to “productDisplayed”, which means the object “currentProduct” in the second VC is nil.
Then I added “performSegue()”.
It still didn’t work. The thing is the second screen was displayed twice. The first time is same with the picture above. And the second time is correct.
But when I tried to click the back button on the left top. It returned to the nil page rather than the ProductDetail page. The screenshot is as follows.
It seems like "prepare" method always being called first then the tableView. How to change the order? If can, this should be fixed I think.
Hope to get your help.
Thank you.
Cause of Problem:
In your storyboard, you may have bound, ProductDetailsViewController with UITableViewCell directly.
It means, upon click/selection of row, it will perform segue (navigation) operation directly.
At the same time, programatically you perform navigation operation using performSegue(withIdentifier: "ProductDetailSegue", sender: self)
Solution:
You have two ways to solve this issue.
I recommend - In your story board, switch segue connection from UITableViewCell to UIViewController (Remove segue connection from UITableViewCell and attach the same segue connection with UIViewController of your tableview)
In your source code, delete/remove this line performSegue(withIdentifier: "ProductDetailSegue", sender: self) and handle data transmission from this function override func prepare(for segue: UIStoryboardSegue, sender: Any?)
I have two segues from one ViewController.
One is supposed to run(crashes for now) when clicking on LogOut Button (Go to LogIn ViewController), another one runs(works good) when clicking on thumbnail of a video.
Since I need to retrieve the video from the server and display it in the ViewController I'm heading to(WatchVideoViewController), I do the code below:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get a reference to a destination View Controller
let detailViewController = segue.destinationViewController as! WatchVideoViewController
// Set the selected video property of the destination view controller
detailViewController.selectedVideo = self.selectedVideo
}
As you might guess this code runs when performing every segue, that's why my LogOut segue crashes.
Could not cast value of type 'AppName.LoginViewController' to 'Appname.WatchVideoViewController'.
Here are pieces of code where I call segues:
#IBAction func pressLogOutButton(sender: AnyObject) {
self.performSegueWithIdentifier("logOutSegue", sender: self)
}
// Handle event when user selects a cell(thumbnail)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Take note of which video is selected
self.selectedVideo = self.videos[indexPath.row]
// Call the segue
self.performSegueWithIdentifier("goToVideo", sender: self)
}
Is there any way to avoid running prepareForSegue when calling pressLogOutButton? Thanks a lot!
Check in your prepareForSegue
if segue.identifier == "logOutSegue"
// perform log out logic
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
i am trying to build my first iOS app with swift. I am stuck at a segue where i want to give the row indexpath to the next page, but the indexpath is "optional(0)" instead of "0". does anyone know why? in the code, there's a print sender. That one says "optional(0)" The variable "viewController.passedValue" is set to 0, the real code is behind it in comments
does anyone know why it gives "Optional(0)"?
Code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let viewController = segue.destinationViewController as! NewsDetailViewController
print(String(sender))
viewController.passedValue = 0 // sender as! int
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("DetailSegue", sender: indexPath.row)
print("HIER")
}
You are calling
performSegueWithIdentifier("DetailSegue", sender: indexPath.row)
And then, iOS is calling your prepareForSegue, in which sender is defined as an AnyObject?, i.e. an optional AnyObject:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
...
}
Thus, when you print sender, it's an optional and thus informs you of such. If you don't want the optional, you could unwrap it (either forced unwrapping or, better, optional binding).
--
As an aside, though, it is a misuse of sender to be storing the indexPath.row there. As the documentation for performSegueWithIdentifier says, the sender is:
The object that you want to use to initiate the segue. This object is made available for informational purposes during the actual segue.
But indexPath.row is not the object that initiated the segue (the table view cell is). I therefore would advise against using the sender to hold the indexPath.row. A more common pattern would be
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destination = segue.destinationViewController as? NewsDetailViewController, let row = tableView.indexPathForSelectedRow?.row {
destination.passedValue = row
}
}
This also has the virtue of giving you the alternative of not defining a didSelectRowAtIndexPath at all, and just represent your segue from the storyboard's cell prototype directly to the NewsDetailViewController scene. If you really want to segue programmatically, you can do that, but it's not necessary. But I would not advise using sender to represent the indexPath.row, but rather the UI control that triggered the segue.