Lê Khánh Vinh Lê Khánh Vinh - 8 months ago 142
iOS Question

IOS present Viewcontroller and pass data inside editActionsForRowAt

Hi I'm developing an app with custom action in tableview cell.

when the user swipe the cell. There will be 2 action: delete and more. I want more action to present a new viewController and pass the object data to the new viewController. How do we achieve that?

I have tried using this

in

viewDidLoad


if let split = self.splitViewController {
let controllers = split.viewControllers
self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}


and
editActionsForRowAt
method

override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

let moreRowAction = UITableViewRowAction(style: .normal, title: "More", handler:{action, indexpath in

if let indexPath = self.tableView.indexPathForSelectedRow {
let object = self.fetchedResultsController.object(at: indexPath)
let controller = self.detailViewController!
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
self.present(controller, animated: true, completion: nil)
}
// self.performSegue(withIdentifier: "showDetail", sender: self)
});
moreRowAction.backgroundColor = UIColor(red: 0.298, green: 0.851, blue: 0.3922, alpha: 1.0);

let deleteRowAction = UITableViewRowAction(style: .destructive, title: "Delete", handler:{action, indexpath in
self.deleteTapped(indexPath: indexPath as NSIndexPath)
});

return [deleteRowAction, moreRowAction];
}


The delete function work but the more action does not work. And help is much appreciate! Thanks

enter image description here

My
prepareforseuge


override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let object = self.fetchedResultsController.object(at: indexPath)
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}

Answer

You can pass your object via the sender parameter to your segue:

let moreRowAction = UITableViewRowAction(style: .normal, title: "More", handler:{action, indexpath in
        let object = self.fetchedResultsController.object(at: indexPath)
        self.performSegue(withIdentifier: "showDetail", sender: object)
    });

Then in prepare(for segue: sender:) -

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetail" {
        guard let navVC = segue.destination as? UINavigationController,
            let destVC = navVC.viewControllers.first as? DetailViewController else {
                return
        }

        var object = sender as? Event
        if object == nil {
            if let indexPath = self.tableView.indexPathForSelectedRow {
                object =  self.fetchedResultsController.object(at: indexPath)
            }
        }
        destVC.detailItem = object
    }
}

The Master-Detail template project uses a navigation controller as the detail destination, so the prepare(for segue) function needs to access the navigation controller's first view controller.

Also, since you are using the same segue for row tap and "more" actions, my code checks for both possibilities - the detail item could be in the sender or in the selected row