Skip to content

Instantly share code, notes, and snippets.

@PimCoumans
Last active February 8, 2024 09:57
Show Gist options
  • Save PimCoumans/823b3fd1b428ff82e3ccd5567c885b40 to your computer and use it in GitHub Desktop.
Save PimCoumans/823b3fd1b428ff82e3ccd5567c885b40 to your computer and use it in GitHub Desktop.
Set primary action handler on UIButton and UIBarButtonItem
import UIKit
public extension UIAction.Identifier {
static let primary = UIAction.Identifier(rawValue: "PrimaryAction")
}
fileprivate extension UIAction {
var handler: UIActionHandler? {
// Tiny bit sketchy: cast UIAction's "handler" value to a ObjC block
typealias ActionHandlerBlock = @convention(block) (UIAction) -> Void
let handler = value(forKey: "handler") as AnyObject
return unsafeBitCast(handler, to: ActionHandlerBlock.self)
}
static func primary(_ handler: @escaping UIActionHandler) -> UIAction {
UIAction(identifier: .primary, handler: handler)
}
}
public protocol PrimaryActionSetting {
@MainActor var primaryAction: UIAction? { get }
/// The handler associated with a `UIAction` with the `.primary` identifier
@MainActor var actionHandler: UIActionHandler? { get set }
/// Updates 'primary' action set to the receiver
/// - Parameter handler: Handler executed with the primary action
@MainActor func setActionHandler(_ handler: UIActionHandler?)
}
extension UIControl: PrimaryActionSetting {
public var primaryAction: UIAction? {
var primaryAction: UIAction?
// Find action that is set as primary
enumerateEventHandlers { action, _, _, stop in
guard action?.identifier == .primary else {
return
}
primaryAction = action
stop = true
}
return primaryAction
}
public var actionHandler: UIActionHandler? {
get {
primaryAction?.handler
}
set {
setActionHandler(newValue)
}
}
public func setActionHandler(_ handler: UIActionHandler?) {
removeAction(identifiedBy: .primary, for: .touchUpInside)
handler.map { addAction(.primary($0), for: .touchUpInside) }
}
}
extension UIBarButtonItem: PrimaryActionSetting {
public var actionHandler: UIActionHandler? {
get { primaryAction?.handler }
set { setActionHandler(newValue) }
}
public func setActionHandler(_ handler: ((UIAction) -> Void)?) {
primaryAction = handler.map { .primary($0) }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment