Presenting UIAlertController from UITableViewCell

2020-02-08 15:58发布

问题:

I am trying to add alerts to a custom UITableViewCell to present an UIAlertView I need to call presentViewController from UIViewController. However, I am unaware of how to gain access to the current UIViewController instance from the UITableViewCell class. The below code is my attempt to do this with an extension.

I get this error

Expression resolved to unused function.

extension UIViewController
{

    class func alertReminden(timeInterval: Int)
    {
        var refreshAlert = UIAlertController(title: "Refresh", message: "All data will be lost.", preferredStyle: UIAlertControllerStyle.Alert)

        refreshAlert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { (action: UIAlertAction!) in
            Alarm.createReminder("Catch the Bus",
                timeInterval: NSDate(timeIntervalSinceNow: Double(timeInterval * 60)))
        }))

        refreshAlert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: { (action: UIAlertAction!) in
            println("Handle Cancel Logic here")
        }))

        UIViewController.presentViewController(refreshAlert)


    }
}

class CustomRouteViewCell: UITableViewCell {

回答1:

You can use this extension to find the viewController that present the cell

extension UIView {
var parentViewController: UIViewController? {
    var parentResponder: UIResponder? = self
    while parentResponder != nil {
        parentResponder = parentResponder!.nextResponder()
        if parentResponder is UIViewController {
            return parentResponder as! UIViewController!
        }
    }
    return nil
}
}

Or use rootViewController to Present:

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(refreshAlert, animated: true, completion: nil)

Swift 4.2 Update

extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder!.next
            if parentResponder is UIViewController {
                return parentResponder as? UIViewController
            }
        }
        return nil
    }
}

Or use rootViewController to Present:

UIApplication.shared.keyWindow?.rootViewController?.present(alertVC, animated: true, completion: nil)


回答2:

Try to replace to this line of code:

Swift 2

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(refreshAlert, animated: true, completion: nil)

Swift 3

UIApplication.shared.keyWindow?.rootViewController?.present(refreshAlert, animated: true, completion: nil)


回答3:

Another way to do this is to declare a protocol and a delegate property in the table view cell class, set the controller as the cells delegate and implement the protocol in the controller which is able to present the alert view controller.



回答4:

Leo's solution worked for me. I've used it to present an AlertView from a Custom collection view cell.

Update for Swift 3.0:

extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder!.next
            if parentResponder is UIViewController {
                return parentResponder as! UIViewController!
            }
        }
        return nil
    }
}

Hope it helps.



回答5:

You could try using a protocol, and delegate, using this method will give you the opportunity to not only present alerts but could give you a better interaction with your view controller in case that you need it on the future. For example:

protocol alerts: class{

    func presentAlert(title:String, message:String)

}

Then in your tableViewCell you'll create something like:

var alertsDelegate : alerts? 

//And whenever you need to present a message call something inside the cell like:

alertsDelegate?.presentAlert(title:"Your title", message:"Your message")

Then in your viewController, firstly set your viewController as alerts

class yourClassName : ViewController, alerts {

    //And add the functions of the protocol
    func presentAlert(title:String, message:String){
        //This is the function that'll be called from the cell
        //Here you can personalize how the alert will be displayed

    }
}

Second, set the delegate for the cell in the "cellForRowAt" method

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifier") as! yourCellClass

    cell.alertsDelegate = self

}

And just like this you can create multiple functions that adapt your need in relation with communication with your viewController or viewControllers.



回答6:

Must be declared protocol and their delegate property in CustomTableViewCell Class and called these properties at the place of UIAlertViewController, and implement these protocol properties in UIViewController.