Adding a closure as target to a UIButton

IosSwiftUibuttonAddtarget

Ios Problem Overview


I have a generic control class which needs to set the completion of the button depending on the view controller.Due to that setLeftButtonActionWithClosure function needs to take as parameter a closure which should be set as action to an unbutton.How would it be possible in Swift since we need to pass the function name as String to action: parameter.

func setLeftButtonActionWithClosure(completion: () -> Void)
{
    self.leftButton.addTarget(<#target: AnyObject?#>, action: <#Selector#>, forControlEvents: <#UIControlEvents#>)
}

Ios Solutions


Solution 1 - Ios

With iOS 14 Apple has finally added this feature to UIKit. However, someone might still want to use this extension because Apple's method signature is suboptimal.

iOS 14:

extension UIControl {
	func addAction(for controlEvents: UIControl.Event = .touchUpInside, _ closure: @escaping()->()) {
		addAction(UIAction { (action: UIAction) in closure() }, for: controlEvents)
	}
}

pre-iOS 14:

extension UIControl {
	func addAction(for controlEvents: UIControl.Event = .touchUpInside, _ closure: @escaping()->()) {
		@objc class ClosureSleeve: NSObject {
			let closure:()->()
			init(_ closure: @escaping()->()) { self.closure = closure }
			@objc func invoke() { closure() }
		}
		let sleeve = ClosureSleeve(closure)
		addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
		objc_setAssociatedObject(self, "\(UUID())", sleeve, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
	}
}

Usage:

button.addAction {
	print("Hello, Closure!")
}

or:

button.addAction(for: .touchUpInside) {
	print("Hello, Closure!")
}

or if avoiding retain loops:

self.button.addAction(for: .touchUpInside) { [unowned self] in
	self.doStuff()
}

(Extension is included here: https://github.com/aepryus/Acheron)

Also note, in theory .primaryActionTriggered could replace .touchUpInside, but it seems to be currently bugged in catalyst, so I'll leave it as is for now.

Solution 2 - Ios

Do Not Use This Answer, See Note Below

NOTE: like @EthanHuang said "This solution doesn't work if you have more than two instances. All actions will be overwrite by the last assignment." Keep in mind this when you develop, i will post another solution soon.

If you want to add a closure as target to a UIButton, you must add a function to UIButton class by using extension

Swift 5

import UIKit    
extension UIButton {
    private func actionHandler(action:(() -> Void)? = nil) {
        struct __ { static var action :(() -> Void)? }
        if action != nil { __.action = action }
        else { __.action?() }
    }	
    @objc private func triggerActionHandler() {
    	self.actionHandler()
   	}	
    func actionHandler(controlEvents control :UIControl.Event, ForAction action:@escaping () -> Void) {
    	self.actionHandler(action: action)
    	self.addTarget(self, action: #selector(triggerActionHandler), for: control)
    }
}

Older

import UIKit

extension UIButton {
    private func actionHandleBlock(action:(() -> Void)? = nil) {
        struct __ {
            static var action :(() -> Void)?
        }
        if action != nil {
            __.action = action
        } else {
            __.action?()
        }
    }
    
    @objc private func triggerActionHandleBlock() {
        self.actionHandleBlock()
    }
    
    func actionHandle(controlEvents control :UIControlEvents, ForAction action:() -> Void) {
        self.actionHandleBlock(action)
        self.addTarget(self, action: "triggerActionHandleBlock", forControlEvents: control)
    }
}

and the call:

 let button = UIButton()
 button.actionHandle(controlEvents: .touchUpInside, 
 ForAction:{() -> Void in
     print("Touch")
 })

Solution 3 - Ios

You can effectively achieve this by subclassing UIButton:

class ActionButton: UIButton {
	var touchDown: ((button: UIButton) -> ())?
	var touchExit: ((button: UIButton) -> ())?
	var touchUp: ((button: UIButton) -> ())?
	
	required init?(coder aDecoder: NSCoder) { fatalError("init(coder:)") }
	override init(frame: CGRect) {
	    super.init(frame: frame)
	    setupButton()
    }
	
	func setupButton() {
        //this is my most common setup, but you can customize to your liking
		addTarget(self, action: #selector(touchDown(_:)), forControlEvents: [.TouchDown, .TouchDragEnter])
		addTarget(self, action: #selector(touchExit(_:)), forControlEvents: [.TouchCancel, .TouchDragExit])
		addTarget(self, action: #selector(touchUp(_:)), forControlEvents: [.TouchUpInside])
	}
	
    //actions
	func touchDown(sender: UIButton) {
		touchDown?(button: sender)
	}
	
	func touchExit(sender: UIButton) {
		touchExit?(button: sender)
	}
	
	func touchUp(sender: UIButton) {
		touchUp?(button: sender)
	}
}

Use:

let button = ActionButton(frame: buttonRect)
button.touchDown = { button in
    print("Touch Down")
}
button.touchExit = { button in
	print("Touch Exit")
}
button.touchUp = { button in
	print("Touch Up")
}

Solution 4 - Ios

Similar solution to those already listed, but perhaps lighter weight and doesn't rely on randomness to generate unique ids:

class ClosureSleeve {
	let closure: ()->()
	
	init (_ closure: @escaping ()->()) {
		self.closure = closure
	}
	
	@objc func invoke () {
		closure()
	}
}

extension UIControl {
	func add (for controlEvents: UIControlEvents, _ closure: @escaping ()->()) {
		let sleeve = ClosureSleeve(closure)
		addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
		objc_setAssociatedObject(self, String(ObjectIdentifier(self).hashValue) + String(controlEvents.rawValue), sleeve,
                             objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
	}
}

Usage:

button.add(for: .touchUpInside) {
	print("Hello, Closure!")
}

Or if avoiding retain loops:

button.add(for: .touchUpInside) { [unowned self] in
	self.doStuff()
}

Solution 5 - Ios

This is now possible on iOS 14. You can pass a UIAction, which has a handler closure, when you create the UIButton:

let action = UIAction(title: "") { action in
    print("Button tapped!")
}

UIButton(type: .system, primaryAction: action)

Or shorter:

UIButton(type: .system, primaryAction: UIAction(title: "") { action in
    print("Button tapped!")
})

Solution 6 - Ios

This is basically Armanoide's answer, above, but with a couple slight changes that are useful for me:

  • the passed-in closure can take a UIButton argument, allowing you to pass in self

  • the functions and arguments are renamed in a way that, for me, clarifies what's going on, for instance by distinguishing a Swift closure from a UIButton action.

     private func setOrTriggerClosure(closure:((button:UIButton) -> Void)? = nil) {
     
       //struct to keep track of current closure
       struct __ {
         static var closure :((button:UIButton) -> Void)?
       }
     
       //if closure has been passed in, set the struct to use it
       if closure != nil {
         __.closure = closure
       } else {
         //otherwise trigger the closure
         __. closure?(button: self)
       }
     }
     @objc private func triggerActionClosure() {
       self.setOrTriggerClosure()
     }
     func setActionTo(closure:(UIButton) -> Void, forEvents :UIControlEvents) {
       self.setOrTriggerClosure(closure)
       self.addTarget(self, action:
         #selector(UIButton.triggerActionClosure),
                      forControlEvents: forEvents)
     }
    

Much props to Armanoide though for some heavy-duty magic here.

Solution 7 - Ios

@Armanoide solution is cool cause it uses trick with struct and static var inside it but it is not perfect if you're reusing one button a few times cause in this case action closure will always store the last handler.

I've fixed it for UIKitPlus library

import UIKit

extension UIControl {
    private func actionHandler(action: (() -> Void)? = nil) {
        struct Storage { static var actions: [Int: (() -> Void)] = [:] }
        if let action = action {
            Storage.actions[hashValue] = action
        } else {
            Storage.actions[hashValue]?()
        }
    }
    
    @objc func triggerActionHandler() {
        actionHandler()
    }
    
    func actionHandler(controlEvents control: UIControl.Event, forAction action: @escaping () -> Void) {
        actionHandler(action: action)
        addTarget(self, action: #selector(triggerActionHandler), for: control)
    }
}

Solution 8 - Ios

I put together a little extension for UIControl that will let you use closures for any action on any UIControl really easily.

You can find it here: https://gist.github.com/nathan-fiscaletti/8308f00ff364b72b6a6dec57c4b13d82

Here are some examples of it in practice:

Setting a Button Action

myButton.action(.touchUpInside, { (sender: UIControl) in
    // do something
})

Detecting a Switch changing Values

mySwitch.action(.valueChanged, { (sender: UIControl) in
    print("Switch State:", mySwitch.isOn)
})

Solution 9 - Ios

Here is a generic swift 5 approach. It has a sender inside action block and eliminates adding action for same event twice

import UIKit

protocol Actionable {
    associatedtype T = Self
    func addAction(for controlEvent: UIControl.Event, action: ((T) -> Void)?)
}

private class ClosureSleeve<T> {
    let closure: ((T) -> Void)?
    let sender: T
    
    init (sender: T, _ closure: ((T) -> Void)?) {
        self.closure = closure
        self.sender = sender
    }
    
    @objc func invoke() {
        closure?(sender)
    }
}

extension Actionable where Self: UIControl {
    func addAction(for controlEvent: UIControl.Event, action: ((Self) -> Void)?) {
        let previousSleeve = objc_getAssociatedObject(self, String(controlEvent.rawValue))
        objc_removeAssociatedObjects(previousSleeve as Any)
        removeTarget(previousSleeve, action: nil, for: controlEvent)
        
        let sleeve = ClosureSleeve(sender: self, action)
        addTarget(sleeve, action: #selector(ClosureSleeve<Self>.invoke), for: controlEvent)
        objc_setAssociatedObject(self, String(controlEvent.rawValue), sleeve, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
    }
}

extension UIControl: Actionable {}

Solution 10 - Ios

Here is a fun variant to the answer by aepryus. My version uses Combine's Cancellable protocol to:

  1. Support removing the registered closure.
  2. Handle memory management thus avoiding the need to use objc_setAssociatedObject.
// Swift 5

import Combine
import UIKit

class BlockObject: NSObject {
    let block: () -> Void

    init(block: @escaping () -> Void) {
        self.block = block
    }

    @objc dynamic func execute() {
        block()
    }
}

extension UIControl {
    func addHandler(
        for controlEvents: UIControl.Event,
        block: @escaping () -> Void)
        -> Cancellable
    {
        let blockObject = BlockObject(block: block)
        addTarget(blockObject, action: #selector(BlockObject.execute), for: controlEvents)

        return AnyCancellable {
            self.removeTarget(blockObject, action: #selector(BlockObject.execute), for: controlEvents)
        }
    }
}

Usage:

let button = UIButton(type: .system)

// Add the handler
let cancellable = button.addHandler(for: .touchUpInside) {
    print("Button pressed!")
}

// Remove the handler
cancellable.cancel()

Don't forget to store a reference to the Cancellable or else the handler will be immediately unregistered.

Solution 11 - Ios

I change a little extension for UIControl that was posted @Nathan F. here

I used objc_setAssociatedObject and objc_getAssociatedObject to get/set closure and i removed global static variable with all created buttons's keys. So now event stored for each instance and released after dealloc

extension UIControl {
    
    typealias Handlers = [UInt:((UIControl) -> Void)]
    
    private enum AssociatedKey {
        static var actionHandlers = "UIControl.actionHandlers"
    }

    /**
     * A map of closures, mapped as  [ event : action ] .
     */

    private var actionHandlers: Handlers {
        get {
            return objc_getAssociatedObject(self, &AssociatedKey.actionHandlers) as? Handlers ?? [:]
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKey.actionHandlers, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }
    }
}

You can find it here: https://gist.github.com/desyatov/6ed83de58ca1146d85fedab461a69b12

Here are some example:

myButton.action(.touchUpInside, { (sender: UIControl) in
    // do something
})

Solution 12 - Ios

Swift

After trying all the solutions, this one worked for me for all cases, even when the button in reusable table view cell

import UIKit

typealias UIButtonTargetClosure = UIButton -> ()

class ClosureWrapper: NSObject {
    let closure: UIButtonTargetClosure
    init(_ closure: UIButtonTargetClosure) {
       self.closure = closure
    }
}

extension UIButton {

private struct AssociatedKeys {
    static var targetClosure = "targetClosure"
}

private var targetClosure: UIButtonTargetClosure? {
    get {
        guard let closureWrapper = objc_getAssociatedObject(self, &AssociatedKeys.targetClosure) as? ClosureWrapper else { return nil }
        return closureWrapper.closure
    }
    set(newValue) {
        guard let newValue = newValue else { return }
        objc_setAssociatedObject(self, &AssociatedKeys.targetClosure, ClosureWrapper(newValue), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

func addTargetClosure(closure: UIButtonTargetClosure) {
    targetClosure = closure
    addTarget(self, action: #selector(UIButton.closureAction), forControlEvents: .TouchUpInside)
}

   func closureAction() {
       guard let targetClosure = targetClosure else { return }
       targetClosure(self)
   }
}

And then you call it like this:

loginButton.addTargetClosure { _ in
        
   // login logics
        
}

Resource: https://medium.com/@jackywangdeveloper/swift-the-right-way-to-add-target-in-uibutton-in-using-closures-877557ed9455

Solution 13 - Ios

My solution.

typealias UIAction = () -> Void;

class Button: UIButton {
    
    public var touchUp :UIAction? {
        didSet {
            self.setup()
        }
    }
    
    func setup() -> Void {
        self.addTarget(self, action: #selector(touchInside), for: .touchUpInside)
    }
    
    @objc private func touchInside() -> Void {
        self.touchUp!()
    }
    
}

Solution 14 - Ios

Swift 4.2 for UIControl and UIGestureRecognizer, and and remove targets through swift extension stored property paradigm.

Wrapper class for the selector

class Target {
    
    private let t: () -> ()
    init(target t: @escaping () -> ()) { self.t = t }
    @objc private func s() { t() }
    
    public var action: Selector {
        return #selector(s)
    }
}

Protocols with associatedtypes so we can hide hide the objc_ code

protocol PropertyProvider {
    associatedtype PropertyType: Any
    
    static var property: PropertyType { get set }
}

protocol ExtensionPropertyStorable: class {
    associatedtype Property: PropertyProvider
}

Extension to make the property default and available

extension ExtensionPropertyStorable {

    typealias Storable = Property.PropertyType

    var property: Storable {
        get { return objc_getAssociatedObject(self, String(describing: type(of: Storable.self))) as? Storable ?? Property.property }
        set { return objc_setAssociatedObject(self, String(describing: type(of: Storable.self)), newValue, .OBJC_ASSOCIATION_RETAIN) }
    }
}

Let us apply the magic

extension UIControl: ExtensionPropertyStorable {

    class Property: PropertyProvider {
        static var property = [String: Target]()
    }

    func addTarget(for controlEvent: UIControl.Event = .touchUpInside, target: @escaping () ->()) {
        let key = String(describing: controlEvent)
        let target = Target(target: target)
        addTarget(target, action: target.action, for: controlEvent)
        property[key] = target
    }

    func removeTarget(for controlEvent: UIControl.Event = .touchUpInside) {
        let key = String(describing: controlEvent)
        let target = property[key]
        removeTarget(target, action: target?.action, for: controlEvent)
        property[key] = nil
    }
}

And to the gestures

extension UIGestureRecognizer: ExtensionPropertyStorable {

    class Property: PropertyProvider {
        static var property: Target?
    }

    func addTarget(target: @escaping () -> ()) {
        let target = Target(target: target)
        addTarget(target, action: target.action)
        property = target
    }

    func removeTarget() {
        let target = property
        removeTarget(target, action: target?.action)
        property = nil
    }
}

Example usage:

button.addTarget {
    print("touch up inside")
}
button.addTarget { [weak self] in
    print("this will only happen once")
    self?.button.removeTarget()
}
button.addTarget(for: .touchDown) {
    print("touch down")
}
slider.addTarget(for: .valueChanged) {
    print("value changed")
}
textView.addTarget(for: .allEditingEvents) { [weak self] in
    self?.editingEvent()
}
gesture.addTarget { [weak self] in
    self?.gestureEvent()
    self?.otherGestureEvent()
    self?.gesture.removeTarget()
}

Solution 15 - Ios

Here's a nice framework for doing this: HandlersKit. The biggest advantage is that you can access to the sender inside the closure without typecasting or optional unwrapping.

Example for UIButton:

import HandlersKit

let button = MyActivityIndicatorButton()
button.onTap { (sender: MyActivityIndicatorButton) in
    sender.showActivityIndicator()
}

Example for UISwitch:

let switchView = UISwitch(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 50.0))
switchView.onChange { isOn in
    print("SwitchView is: \(isOn)")
}

Solution 16 - Ios

I have started to use Armanoide's answer disregarding the fact that it'll be overridden by the second assignment, mainly because at first I needed it somewhere specific which it didn't matter much. But it started to fall apart.

I've came up with a new implementation using AssicatedObjects which doesn't have this limitation, I think has a smarter syntax, but it's not a complete solution:

Here it is:

typealias ButtonAction = () -> Void

fileprivate struct AssociatedKeys {
  static var touchUp = "touchUp"
}

fileprivate class ClosureWrapper {
  var closure: ButtonAction?

  init(_ closure: ButtonAction?) {
    self.closure = closure
  }
}

extension UIControl {

  @objc private func performTouchUp() {

    guard let action = touchUp else {
      return
    }

    action()

  }

  var touchUp: ButtonAction? {

    get {
      
      let closure = objc_getAssociatedObject(self, &AssociatedKeys.touchUp)
      guard let action = closure as? ClosureWrapper else{
        return nil
      }
      return action.closure
    }

    set {
      if let action = newValue {
        let closure = ClosureWrapper(action)
        objc_setAssociatedObject(
          self,
          &AssociatedKeys.touchUp,
          closure as ClosureWrapper,
          .OBJC_ASSOCIATION_RETAIN_NONATOMIC
        )
        self.addTarget(self, action: #selector(performTouchUp), for: .touchUpInside)
      } else {        
        self.removeTarget(self, action: #selector(performTouchUp), for: .touchUpInside)
      }

    }
  }

}

As you can see, I've decided to make a dedicated case for touchUpInside. I know controls have more events than this one, but who are we kidding? do we need actions for every one of them?! It's much simpler this way.

Usage example:

okBtn.touchUp = {
      print("OK")
    }

In any case, if you want to extend this answer you can either make a Set of actions for all the event types, or add more event's properties for other events, it's relatively straightforward.

Cheers, M.

Solution 17 - Ios

One more optimisation (useful if you use it in many places and don't want to duplicate call to objc_setAssociatedObject). It allows us to not worry about a dirty part of objc_setAssociatedObject and keeps it inside ClosureSleeve's constructor:

class ClosureSleeve {
    let closure: () -> Void
    
    init(
        for object: AnyObject,
        _ closure: @escaping () -> Void
        ) {

        self.closure = closure

        objc_setAssociatedObject(
            object,
            String(format: "[%d]", arc4random()),
            self,
            objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN
        )
    }
    
    @objc func invoke () {
        closure()
    }
}

So your extension will look a tiny bit cleaner:

extension UIControl {
    func add(
        for controlEvents: UIControlEvents,
        _ closure: @escaping ()->()
        ) {

        let sleeve = ClosureSleeve(
            for: self,
            closure
        )
        addTarget(
            sleeve,
            action: #selector(ClosureSleeve.invoke),
            for: controlEvents
        )
    }
}

Solution 18 - Ios

class ViewController : UIViewController {
  var aButton: UIButton!

  var assignedClosure: (() -> Void)? = nil

  override func loadView() {
    let view = UIView()
    view.backgroundColor = .white

    aButton = UIButton()
    aButton.frame = CGRect(x: 95, y: 200, width: 200, height: 20)
    aButton.backgroundColor = UIColor.red

    aButton.addTarget(self, action: .buttonTapped, for: .touchUpInside)

    view.addSubview(aButton)
    self.view = view
  }

  func fizzleButtonOn(events: UIControlEvents, with: @escaping (() -> Void)) {
    assignedClosure = with
    aButton.removeTarget(self, action: .buttonTapped, for: .allEvents)
    aButton.addTarget(self, action: .buttonTapped, for: events)
  }

  @objc func buttonTapped() {
    guard let closure = assignedClosure else {
      debugPrint("original tap")
      return
    }
    closure()
  }
} 

fileprivate extension Selector {
  static let buttonTapped = #selector(ViewController.buttonTapped)
}

Then at some point in your app's lifecycle, you'll mutate the instances' closure. Here's an example

fizzleButtonOn(events: .touchUpInside, with: { debugPrint("a new tap action") })

Solution 19 - Ios

Below extension is for add tap gesture to UIView's level, which will work on anything that based of UIView.

Note: I found this solution years ago on StackOverflow too, but now I can't seem to find the original source.

extension UIView {
    
    // In order to create computed properties for extensions, we need a key to
    // store and access the stored property
    fileprivate struct AssociatedObjectKeys {
        static var tapGestureRecognizer = "MediaViewerAssociatedObjectKey_mediaViewer"
    }
    
    fileprivate typealias Action = (() -> Void)?
    
    // Set our computed property type to a closure
    fileprivate var tapGestureRecognizerAction: Action? {
        set {
            if let newValue = newValue {
                // Computed properties get stored as associated objects
                objc_setAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
            }
        }
        get {
            let tapGestureRecognizerActionInstance = objc_getAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer) as? Action
            return tapGestureRecognizerActionInstance
        }
    }
    
    // This is the meat of the sauce, here we create the tap gesture recognizer and
    // store the closure the user passed to us in the associated object we declared above
    public func addTapGestureRecognizer(action: (() -> Void)?) {
        self.isUserInteractionEnabled = true
        self.tapGestureRecognizerAction = action
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
        tapGestureRecognizer.cancelsTouchesInView = false
        self.addGestureRecognizer(tapGestureRecognizer)
    }
    
    // Every time the user taps on the UIImageView, this function gets called,
    // which triggers the closure we stored
    @objc fileprivate func handleTapGesture(sender: UITapGestureRecognizer) {
        if let action = self.tapGestureRecognizerAction {
            action?()
        } else {
            print("no action")
        }
    }
    
}

Usage example:

let button = UIButton()
button.addTapGestureRecognizer {
    print("tapped")
}
        
let label = UILabel()
label.addTapGestureRecognizer {
    print("label tapped")
}           

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIlker BaltaciView Question on Stackoverflow
Solution 1 - IosaepryusView Answer on Stackoverflow
Solution 2 - IosArmanoideView Answer on Stackoverflow
Solution 3 - IosjacobView Answer on Stackoverflow
Solution 4 - IosGrant KaminView Answer on Stackoverflow
Solution 5 - IosHejaziView Answer on Stackoverflow
Solution 6 - IosLe Mot JuicedView Answer on Stackoverflow
Solution 7 - IosimikeView Answer on Stackoverflow
Solution 8 - IosNathan F.View Answer on Stackoverflow
Solution 9 - IosYaroslav L'vovView Answer on Stackoverflow
Solution 10 - IosSebastian CelisView Answer on Stackoverflow
Solution 11 - IosAlexanderView Answer on Stackoverflow
Solution 12 - IosMusa almatriView Answer on Stackoverflow
Solution 13 - IosLightinDarknessJavaView Answer on Stackoverflow
Solution 14 - IosEric ArmstrongView Answer on Stackoverflow
Solution 15 - IosГена КуприяновView Answer on Stackoverflow
Solution 16 - IosM. PorooshaniView Answer on Stackoverflow
Solution 17 - IosMaciek CzarnikView Answer on Stackoverflow
Solution 18 - IosjnblanchardView Answer on Stackoverflow
Solution 19 - Ioschhay sothearaView Answer on Stackoverflow