Reputation: 177
I added a button on my custom tableViewCell and i want that after the button is tapped it pass data according to the cell on which the button is located, so to find out on which cell is the button i added a tag, but i'm getting this error
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToLast" && sender is IndexPath {
let dvc = segue.destination as! FinalClass
dvc.index = (sender as! IndexPath).row
dvc.places = sortedArray
dvc.userLocation = currentLocation
}
if segue.identifier == "goToReview" {
let index3 = IndexPath(row: sender.tag, section: 0)
let rev = segue.destination as! ReviewClass
}
}
How can i adjust it?
(cell.reviewButton.tag = indexPath.row
) this is the tag i added in my cellForRowAt
UPDATE
this is the button action in my VC
@IBAction func ReviewButtonTap(_ sender: UIButton) {
performSegue(withIdentifier: "goToReview" , sender: self)
}
and this is the outlet in my custom tableViewCell class
@IBOutlet weak var reviewButton: UIButton!
i do not understand how can i associate this button with
else if segue.identifier == "goToReview", let button = sender as? UIButton, let rev = segue.destination as? ReviewClass {
let index3 = IndexPath(row: button.tag, section: 0)
Upvotes: 1
Views: 3052
Reputation: 1593
You can get UIButton object from sender then UIButton object have tag property to access.
let button = sender as? UIButton
let index3 = IndexPath(row: button?.tag ?? 0, section: 0)
Upvotes: 0
Reputation: 1
For manage this problem first you need to first assign tag of button in cell for row which is you already done.
cell.reviewButton.tag = indexPath.row
After that you can add target actions on your button in the cell for row
cell.reviewButton.addTarget(self, action:#selector(self.
func_Navigate(_:)), for:UIControlEvents.touchUpInside)
Out side cell for row make implement one function like that:-
@IBAction func func_Navigate(_ sender: UIButton)
{
If sender.tag == 0
{
\\ here sender.tag = 0 means button belong from fist row of your table view. you can perform navigation like that :-
self.performSegue(withIdentifier: "goToLast", sender: self)
}
else If sender.tag == 1
{
\\ here sender.tag = 1 means button belong from second row of your table view. you can perform navigation like that :-
self.performSegue(withIdentifier: "goToReview", sender: self)
}
Upvotes: 0
Reputation: 1701
Just you need to change your segue method with below method
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToLast" && sender is IndexPath {
let dvc = segue.destination as! FinalClass
dvc.index = (sender as! IndexPath).row
dvc.places = sortedArray
dvc.userLocation = currentLocation
}
if segue.identifier == "goToReview" {
let index3 = IndexPath(row: (sender as! UIButton).tag, section: 0)
let rev = segue.destination as! ReviewClass
}
}
Upvotes: 0
Reputation: 285082
Force downcast the optional Any
to expected UIButton
and IndexPath
and use an else
clause instead of if
twice
if segue.identifier == "goToLast" {
let dvc = segue.destination as! FinalClass
let indexPath = sender as! IndexPath
dvc.index = indexPath.row
dvc.places = sortedArray
dvc.userLocation = currentLocation
}
else if segue.identifier == "goToReview" {
let button = sender as! UIButton
let index3 = IndexPath(row: button.tag, section: 0)
let rev = segue.destination as! ReviewClass
}
or use a switch
switch segue.identifier {
case "goToLast":
let dvc = segue.destination as! FinalClass
let indexPath = sender as! IndexPath
dvc.index = indexPath.row
dvc.places = sortedArray
dvc.userLocation = currentLocation
case "goToReview":
let button = sender as! UIButton
let index3 = IndexPath(row: button.tag, section: 0)
let rev = segue.destination as! ReviewClass
default: break
}
The code must not crash. If it does you made a design mistake.
Edit
You have to pass the UIButton
instance (the sender
) from the IBAction
to the sender
parameter of performSegue
. The outlet is irrelevant.
performSegue(withIdentifier: "goToReview" , sender: sender)
Upvotes: 1
Reputation: 16774
It is common you will provide a sender as Any
in your method in cases where it can be different object. In such case you will need to typecast it to a specific object which is best done as let button = sender as? UIButton
in swift.
By doing so you will receive an optional value and its tag would be button?.tag
and its type Int?
which then again disallows you to create an index path.
So a proper way for this method should be as follows:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToLast", let indexPath = sender as? IndexPath {
let dvc = segue.destination as! FinalClass
dvc.index = indexPath.row
dvc.places = sortedArray
dvc.userLocation = currentLocation
} else if segue.identifier == "goToReview", let button = sender as? UIButton {
let index3 = IndexPath(row: button.tag, section: 0)
let rev = segue.destination as! ReviewClass
}
}
Note that I have changed both if
statements and managed to even remove an extra force-unwrap (The !
thing). If you don't mind force-unwrapping which crashes your app when incorrect then you could as well just do:
let index3 = IndexPath(row: (sender as! UIButton).tag, section: 0)
But I suggest you avoid all force-unwrapping to improve stability. For your case that would be:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToLast", let indexPath = sender as? IndexPath, let dvc = segue.destination as? FinalClass {
dvc.index = indexPath.row
dvc.places = sortedArray
dvc.userLocation = currentLocation
} else if segue.identifier == "goToReview", let button = sender as? UIButton, let rev = segue.destination as? ReviewClass {
let index3 = IndexPath(row: button.tag, section: 0)
} else {
print("ERROR: Incorrect configuration!") // Put a breakpoint here and analyze what was the identifier and what the sender so none of the statements were hit
}
}
Upvotes: 1