Home > Blockchain >  Passing selector to a different class in swift5
Passing selector to a different class in swift5

Time:09-16

I have a view controller which with a button to restore the default settings. Contained within the same VC is the function restoreDefaults()

   @IBAction func resetBtnAct(_ sender: Any) {
       
        let alert = AlertGenFromVC(sendingVC: self).generateAlert(
            titleIn: "Warning!",
            messageIn: "You are about to reset to the default settings. You will not be able to undo this action.",
            actionTitle1: "Reset", actionAct1: #selector(self.restoreDefaults), actionTitle2: "Cancel", actionAct2: nil)
        
        self.present(
            alert,
            animated: false,
            completion: nil)
    }

I am passing this to another class which is then used to present the alert controller

class AlertGenFromVC {
    
    
    
    var originVC: AnyObject?
    
    var originTextField: UITextField?
    
        
    init(sendingVC: AnyObject) {
         originVC = sendingVC
          
        
        
    }
    
    func generateAlert(titleIn: String, messageIn: String, actionTitle1:String, actionAct1:Selector, actionTitle2:String?, actionAct2:Selector?) -> UIAlertController {
        
        let alert = UIAlertController(
            title: titleIn,
            message: messageIn,
            preferredStyle: .alert)
        
       
      
        // Add first action
        
        let action1 = UIAlertAction(title: actionTitle1, style: UIAlertAction.Style.default, handler: {(action) in actionAct1
       })
      
        alert.addAction(action1)
        
        //Action 2
        
        if actionTitle2 != nil  && actionAct2 != nil {
            print("act2")
            
            let action2 = UIAlertAction(title: actionTitle2, style: UIAlertAction.Style.default, handler: {action in actionAct2
                
            })
            
            alert.addAction(action2)
            
        } else if actionTitle2 != nil  && actionAct2 == nil {
            print("action 2 nil")
            let action2 = UIAlertAction(title: actionTitle2, style: UIAlertAction.Style.default, handler: nil)
            alert.addAction(action2)
        
        }
        
        let popover = alert.popoverPresentationController
            popover?.sourceView = self.originVC as? UIView
        popover?.sourceRect = CGRect(x: 32, y: 32, width: 64, height: 64)
        
        
        return alert
        
        
    }
    
}

Action 1 and 2 both show a warning "Expression of type 'Selector' is unused".

The alert is presented fine but there is no action on clicking the button. Am i defining the selectors incorrectly or am I doing something else wrong? All suggestions gratefully received.

CodePudding user response:

An extra class to create an alert controller to be presented by an UIViewController is an unswifty approach.

A better one is an extension of UIViewController

extension UIViewController {

    func showAlert(titleIn: String,
                   messageIn: String,
                   actionTitle1: String,
                   actionAct1: (() -> Void)? = nil,
                   actionTitle2: String?,
                   actionAct2: (() -> Void)? = nil) {
    
    let alert = UIAlertController(
        title: titleIn,
        message: messageIn,
        preferredStyle: .alert)
    
    // Add first action
    
    let action1 = UIAlertAction(title: actionTitle1, style: .default, handler: { _ in actionAct1?() })
    alert.addAction(action1)
    
    //Action 2
    
    if let title2 = actionTitle2 {
        print(title2)
        let action2 = UIAlertAction(title: title2, style: .default, handler: { _ in actionAct2?() })
        alert.addAction(action2)
    }
    
    let popover = alert.popoverPresentationController
    popover?.sourceView = self.view
    popover?.sourceRect = CGRect(x: 32, y: 32, width: 64, height: 64)
    
    self.present(alert, animated: true, completion: nil)
}

and use it

func restoreDefaults() {
    // do something
}

func resetBtnAct(_ sender: Any) {
   
    self.showAlert(
        titleIn: "Warning!",
        messageIn: "You are about to reset to the default settings. You will not be able to undo this action.",
        actionTitle1: "Reset",
        actionAct1: restoreDefaults,
        actionTitle2: "Cancel")
}

CodePudding user response:

You can directly pass the function as a parameter. For example like this:

let alert = AlertGenFromVC(sendingVC: self).generateAlert(
            titleIn: "Warning!",
            messageIn: "You are about to reset to the default settings. You will not be able to undo this action.",
            actionTitle1: "Reset", actionAct1: self.restoreDefaults, actionTitle2: "Cancel", actionAct2: nil)

The function generateAlert would look like this:

func generateAlert(titleIn: String, messageIn: String, actionTitle1:String, actionAct1: @escaping ((UIAlertAction) -> Void), actionTitle2:String?, actionAct2: ((UIAlertAction) -> Void)? = nil) -> UIAlertController {
    
    let alert = UIAlertController(
        title: titleIn,
        message: messageIn,
        preferredStyle: .alert)
    
   
  
    // Add first action
    
    let action1 = UIAlertAction(title: actionTitle1, style: UIAlertAction.Style.default, handler: actionAct1)
  • Related