Bad Exception on swipe action cell Swift - swift

I'm making an app that is sending information about text inside of cells to a WebViewController using swipe actions. The swipe action is:
let sendToWebsite = UITableViewRowAction(style: .Default, title: "Website")
{ (action, indexPath) in
self.performSegueWithIdentifier("yourSegueIdentifier", sender: nil)
}
sendToWebsite.backgroundColor = UIColor.blueColor()
return [sendToWebsite]
}
This works fine but I also have two segues coming from the same View Controller, to two other VC's. The first segue(recipeDetail) is when you tap directly on the cell and works fine, but the second segue(yourSegueIdentifier) is a button that appears when you activate the slide action on the cell and does't work.
the segues:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "recipeDetail") {
let indexPath = self.tableView!.indexPathForSelectedRow
let destinationViewController: DetailViewController = segue.destinationViewController as! DetailViewController
destinationViewController.recipe = recipes[indexPath!.row]
}
else if segue.identifier == "yourSegueIdentifier"
{
let indexPath = self.tableView!.indexPathForSelectedRow
let nextVC: WebViewController = segue.destinationViewController as! WebViewController
nextVC.recipe = recipes[indexPath!.row]
}
}
On the line
nextVC.recipe = recipes[indexPath!.row]
indexPath is coming out as nil and giving the following error message

Well it looks like on the swipe action, the tableView doesn't register the "indexPathForSelectedRow" method.
What you could alternatively do is setup a global swipeIndex variable
class ViewController: UIViewController{
var swipeIndex : Int!
//Code, code, code...
and then set it once the swipe action is called.
let sendToWebsite = UITableViewRowAction(style: .Default, title: "Website")
{ (action, indexPath) in
self.swipeIndex = indexPath.row
self.performSegueWithIdentifier("yourSegueIdentifier", sender: nil)
}
sendToWebsite.backgroundColor = UIColor.blueColor()
return [sendToWebsite]
}
and then:
else if segue.identifier == "yourSegueIdentifier"
{
let indexPath = self.tableView!.indexPathForSelectedRow
let nextVC: WebViewController = segue.destinationViewController as! WebViewController
nextVC.recipe = recipies[self.swipeIndex]
}
}

Related

if let editItemVC = segue.destination as? ItemDetailViewController {} doesn't work

i have two segues in this tableViewController, but the downcasting in prepare(for: segue) doesn't work.
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
print("into segue")
super.prepare(for: segue, sender: sender)
switch segue.identifier {
case "addItem":
print("addItem Segue")
if let addItemVC = segue.destination as? ItemDetailViewController {
print("if let done")
addItemVC.container = container
} else {
print("WTF")
}
case "editItem":
print("editItem Segue")
if let editItemVC = segue.destination as? ItemDetailViewController {
guard let selectedItemCell = sender as? PriorityListTVCell else {
fatalError("Unexpected sender: \(String(describing: sender))")
}
guard let indexPath = tableView.indexPath(for: selectedItemCell) else {
fatalError("The selected cell is not being displayed by the table")
}
editItemVC.editedInfo = list[indexPath.row]
print("passed indexPath.row: \(indexPath.row)")
editItemVC.container = container
}
default:
break
}
}
if i click "add" button, in the console it'll print out
into segue
addItem Segue
WTF
not sure why the downcasting doesn't work, does it have anything to do with segue types of destination?
Thanks for help!
This
if let addItemVC = segue.destination as? ItemDetailViewController {
won't work if the destination vc isn't of type ItemDetailViewController meaning you need to assign the class name in IB , for help you can do
print(type(of:segue.destination))
For navigation do
if let nav = segue.destination as? UINavigationController ,
let addItemVC = nav.viewControllers?.first as? ItemDetailViewController {}

TableView cell, swipeactions and different segues Swift 4

In ViewController A I have a TableView with two trailingSwipeActions and one leadingSwipeAction. If you tap on the cell there is a segue to ViewController B. The trailingSwipeActions call ActionSheets, handled inside ViewController A. The segue is executed from within the 'prepare for segue' function. That all works super.
Now I want to add another segue for if you perform the leadingSwipeAction. That segue has to lead to ViewController C. I can't add another segue in the Storyboard, from the customcell to ViewController C... then when I click on the cell... just one segue gets called (and not the other). So... what to do.
Here is the relevant part of my code:
override func tableView(_ tableView: UITableView,
leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
let weightAction = UIContextualAction(style: .normal, title: "Gewicht", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
success(true)
})
weightAction.image = UIImage(named: "Scale")
weightAction.backgroundColor = UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1)
return UISwipeActionsConfiguration(actions: [weightAction])
}
What I want: if you tap on the icon named 'Scale' you trigger a segue to ViewController C.
Also my code for the 'prepare for segue' function (for the segue to ViewController B):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailSegue"{
let rowClicked = (self.tableView.indexPathForSelectedRow?.row)!
let destVC = segue.destination as! UINavigationController
let slideVC = destVC.topViewController as! detailViewController
slideVC.araKuiken = araKuikens[rowClicked]
}
}
So how can I add a segue to ViewController C, that gets called when I tap the 'scale' button?
If you want your weightAction to trigger a segue to viewController C you will just need to perform that segue inside the handler block like so:
let weightAction = UIContextualAction(style: .normal, title: "Gewicht", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
self.performSegue(withIdentifier: "viewControllerC", sender: ac)
success(true)
})
Then, in your prepare code you'd want to handle this possibility as well:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailSegue"{
let rowClicked = (self.tableView.indexPathForSelectedRow?.row)!
let destVC = segue.destination as! UINavigationController
let slideVC = destVC.topViewController as! detailViewController
slideVC.araKuiken = araKuikens[rowClicked]
} else if segue.identifier == "viewControllerC" {
//Perform your preparation code here
}
}
Of course you'll still need to create the segue in the Storyboard, as you mentioned, by dragging from the yellow circle at the top of viewControllerA to viewControllerC, and giving it the proper name (I used "viewControllerC" as an example).
I saved the indexPath in a variable when the cell displays the side menu leadingSwipeActionsConfigurationForRowAt()
Then I use it in the Prepare() method
if let indexPath = self.indexPathSelected {
if segue.identifier == "IdentifierA" {
}else if segue.identifier == "IdentifierB" {
let destino = segue.destination as! VCdestinarion
destino.intLibro = Int(self.arrData[indexPath.row][1]
}
}
This worked for my.
Regards

SWReveal TableViewController - how to launch to different ViewControllers?

I'm using the SWReveal slide out menuing system.
The menu is generated from an array, and all works fine. E.g.
arrayOfCellData = [cellData(cell : 1, text : "Angles", image : #imageLiteral(resourceName: "Angles.png")),
cellData(cell : 2, text : "Area", image : #imageLiteral(resourceName: "Area.png")),
When I tap on a particular menu option I want to segue to a different ViewController. Here is the code that I have been using which doesn't work.
The idea that Row 1 invokes segue A and 2 segue B...
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if(indexPath.row == 1 ){
let vc: AnyObject! = self.storyboard?.instantiateViewController(withIdentifier: "A")
self.performSegue(withIdentifier: "A", sender: self)
self.show(vc as! A, sender: vc)
NSLog("A")
}
if(indexPath.row == 2 ){
let vc: AnyObject! = self.storyboard?.instantiateViewController(withIdentifier: "B")
self.performSegue(withIdentifier: "B", sender: self)
self.show(vc as! B, sender: vc)
NSLog("B")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = " "
navigationItem.backBarButtonItem = backItem
if segue.identifier == "A", let nextScene = segue.destination as? A {
nextScene.categoryCounter = 1
}
if segue.identifier == "B", let nextScene = segue.destination as? B {
nextScene.categoryCounter = 2
}
}
With SWRevealViewController it is best to not use segues in storyboard and instead contract your reveal view controller programmatically. Try this, in your didSelectRowAtIndexPath method add the following to your code.
// Here I get the view controllers I am interested in
let frontStoryboard = UIStoryboard(name: "YourStoryboard", bundle: .main)
let frontVC = frontStoryboard.instantiateInitialViewController()
let rearStoryboard = UIStoryboard(name: "YourOtherStoryboard", bundle: .main)
let rearVC = rearStoryboard.instantiateInitialViewController()
// Construct the SWRevealViewController with your view controllers
if let revealVC = SWRevealViewController(rearViewController: rearVC, frontViewController: frontVC) {
revealVC.modalTransitionStyle = .crossDissolve // Set segue transition
present(revealVC, animated: true, completion: nil) // Segue to view controller
}

Pass image from collectionview to VC

I've tried a lot of methods i couldn't get it to work
ViewController 1 have : Collectionview > Cell > image inside the cell
ViewController 2 want to display the image which in VC 1
When you click on cell it has segue to push you to VC 2
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popup" {
let viewController: friendpopup = segue.destination as! friendpopup
let indexPath = sender as! NSIndexPath
let nicknamex = self.nicknameArray[indexPath.row]
let usernamex = self.userArray[indexPath.row]
let photox = self.friendsphotos[indexPath.row] // the photos PFFiles i think
viewController.snick = nicknamex
viewController.suser = usernamex
viewController.sphoto = // ????
}
nickname and user works fine only the image i couldn't display it.
I tried when you click on cell it will send the image to var but isn't working
var photovar:UIImage!
didSelectItemAt( self.photovar = cell.profilepic.image)
then in prepareSegue( viewcontroller.sphoto = self.photovar)
isn't woking, Anyone could help me to fix that to display the image? Thanks
Tightening up your code a bit....
First VC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popup" {
if let vc = segue.destination as? friendpopup {
let indexPath = sender as! NSIndexPath
vc.snick = self.nicknameArray[indexPath.row]
vc.suser = self.userArray[indexPath.row]
vc.sphoto = self.friendsphotos[indexPath.row]
}
}
}
Second VC:
// making assumptions on variable types
var snick:String!
var suser:String!
var sphoto:UIImage!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// do work here
if sphoto != nil {
imageView.image = sPhoto
} else {
// set a default image here
}
}
Most of this is similar to your code, but one last note - if the first 2 properties are coming across correctly, check in the first VC that you are pulling the image out properly.

How to Push ViewController in UITableViewCell's #IBAction func

I have a UITableViewController and UITableViewCell and Cell's XIB Files.
My question is how to push UIViewController from cell?
in UITableViewCell.
#IBAction func pushBtnTapped(sender: AnyObject) {
// navigate to post view controller
let guest = self.storyboard?.instantiateViewControllerWithIdentifier("GuestCollectionVC") as! GuestCollectionVC
self.navigationController?.pushViewController(guest, animated: true)
}
I got an error message. self.storyboard is not UITableCell's member.
I know there is another way to implement this. But I have to implement in TableViewCell.
Ideally you'd push from the table view controller, in the didSelectRowAtIndexPath method call. Why do you say you have to implement it in the cell? There are other ways you could do that but from what you're saying this might be the best shot...
self.performSegueWithIdentifier("YourSegueId", sender: nil)
Then in prepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//get the index path of the selected row
let indexPath = self.tableView.indexPathForSelectedRow
//just an example if you want to pass something to the other vc
let item = self.responseItems[indexPath!.row]
if segue.identifier == "YourSegueId" {
YourVC = segue.destinationViewController as! YourVC
YourVC.item = item
}
}
If you want to do it from the button you could do something like this in the prepareForSegue method... now you have the button and its index path
let button = sender as! UIButton
let view = button.superview
let cell = view?.superview as! YourCell
let indexPath = tableView.indexPathForCell(cell)