Search code examples
swiftextension-methodsuialertcontrolleruiactionsheetuialertaction

How to create a reusable UIAlert ActionSheet as an UIViewController extension?


I would like to create an action sheet that can be used several time in my code. To do so, I need to be able to use functions according to the action sheet title. Is there a way to pass functions as a parameter array like the "title" parameter?

//MARK: - UIAlert action sheet title
enum ActionSheetLabel: String {
  case camera = "Camera"
  case photoLibrary = "Album"
  case cancel = "Cancel"
}



class CameraHandler {
static let cameraHandler = CameraHandler()
func openCamera() { }
func openPhotoLibrary() { }
}


//MARK: - Alert that shows an action sheet with cancel
extension UIViewController {
  func showActionSheetWithCancel(vc: UIViewController, title: [ActionSheetLabel] /*Make a function parameter here to match title*/) {
    let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

for value in title {
  actionSheet.addAction(UIAlertAction(title: value.rawValue, style: .default, handler: {
    (alert: UIAlertAction!) -> Void in

    //Use the parameter function here to match title

  }))
}

actionSheet.addAction(UIAlertAction(title: ActionSheetLabel.cancel.rawValue, style: .cancel, handler: nil))
vc.present(actionSheet, animated: true, completion: nil)
  }
}

Solution

  • I have find out the best way to add an action sheet with cancel and as much action as needed.

    Create an UIViewController extension with type alias:

    //MARK: - Alert that shows an action sheet with cancel 
    extension UIViewController {
      typealias AlertAction = () -> ()
      typealias AlertButtonAction = (ActionSheetLabel, AlertAction)
    
      func showActionSheetWithCancel(titleAndAction: [AlertButtonAction]) {
        let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
    
    for value in titleAndAction {
      actionSheet.addAction(UIAlertAction(title: value.0.rawValue, style: .default, handler: {
      (alert: UIAlertAction!) -> Void in
    
        value.1()
    
    }))
    }
    actionSheet.addAction(UIAlertAction(title: ActionSheetLabel.cancel.rawValue, style: .cancel, handler: nil))
    self.present(actionSheet, animated: true, completion: nil)
      }
    }
    

    Then, in the class or other place where you want to use it, add the method this way:

    //MARK: - UIAlert action sheet title
    enum ActionSheetLabel: String {
      case camera = "Camera"
      case photoLibrary = "Album"
      case cancel = "Cancel"
    }
    
    //MARK: - Class example where to use the action sheet action
    class CameraHandler {
    
    fileprivate let currentVC: UIViewController!
    
    func openCamera() { 
    // Open user camera
    }
    func openPhotoLibrary() { 
    // Open user photo library
    }
    
      // Method example of this action sheet
      func showActionSheetWithCameraAndLibrary(vc: UIViewController) {
    
        //This is the way to use the extension
        vc.showActionSheetWithCancel(titleAndAction: [
          (ActionSheetLabel.camera, { [weak self] in self?.openCamera() }),
          (ActionSheetLabel.photoLibrary, { [weak self] in self?.openPhotoLibrary() })
          ])
      }
    }