'Getting the current UIButton menu selected item

I have a uibutton with a menu and several actions.

Whenever the user select a menu item I want to fetch it and print it.

This is my button:

   private lazy var measurementField: UIButton = {
    let saveAction = { (action: UIAction) in
        //action
    }
    let saveMenu = UIMenu(children: [
        UIAction(title: Ingredient.Measurements.oz.rawValue, image: nil, handler: saveAction),
        UIAction(title: Ingredient.Measurements.grams.rawValue, image: nil, handler: saveAction),
        UIAction(title: Ingredient.Measurements.cups.rawValue, image: nil, handler: saveAction),
        UIAction(title: Ingredient.Measurements.tsp.rawValue, image: nil, handler: saveAction),
        UIAction(title: Ingredient.Measurements.tbsp.rawValue, image: nil, handler: saveAction),
        UIAction(title: Ingredient.Measurements.quarts.rawValue, image: nil, handler: saveAction),
        UIAction(title: Ingredient.Measurements.pints.rawValue, image: nil, handler: saveAction),
    ])
    var config = UIButton.Configuration.filled()
    config.baseBackgroundColor = .label
    let button = UIButton(configuration: config)
    button.menu = saveMenu
    button.showsMenuAsPrimaryAction = true
    button.changesSelectionAsPrimaryAction = true
    button.addTarget(CreateFormViewController(), action: #selector(CreateFormViewController.linkData), for: .touchUpInside)
    return button
}()

This is my selector (the action that should be triggered):

@objc public func linkData(..more params... , _ sender:UIButton?) { 
    ...
    print(sender?.menu?.title)
    ...
}

It only prints 'nil' tho. How can I fetch that menu-selected item?



Solution 1:[1]

You can fetch the selected item into the action block

let saveAction = { (action: UIAction) in
    //action
    print(action.title)
}

Solution 2:[2]

UIMenu doesn't have 'selectedItem'. When your action method linkData is called you are trying to print title of menu, not title of UIAction. If you look on full initializer of UIMenu, you will see that UIMenu initializer has 'title' property, which by default is setted as "" (empty String).

public convenience init(title: String = "", image: UIImage? = nil, identifier: UIMenu.Identifier? = nil, options: UIMenu.Options = [], children: [UIMenuElement] = [])

If you want to print a title of your action item, you have to do it in your handler closure:

let saveAction = { (action: UIAction) in
  //do your stuff here
}

p.s. If you want to make references to self or any other class-object in your controller, don't forget to capture this reference as unowned/weak to avoid retain cycle:

let saveAction = { [weak self] (action: UIAction) in
  self?.printActionItemTitle(action.title)
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dhaval Patoliya
Solution 2