You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何UIDeferredMenuElement无法加入UIAction数组却可组合传入UIMenu?

问题:UIDeferredMenuElement无法追加到UIAction数组,但可直接传入UIMenu的原因?

你定义了一个UIAction类型的数组ele,并将其赋值给按钮菜单:

var ele = // 一个 [UIAction] 类型数组
yourButton.menu = UIMenu(children: ele)

为监听菜单打开事件,你用常规技巧创建了UIDeferredMenuElement实例:

let trick = UIDeferredMenuElement.uncached({completion in
    print("menu opened")
    completion([])
})

但执行ele.append(trick)时会报错:

[X] Cannot convert value of type 'UIDeferredMenuElement' to expected argument type 'UIAction'

不过直接把它和UIAction组合传入UIMenu却能正常运行,比如:

aButton.menu = UIMenu(children: [ele[0], ele[1], ele[2], trick])

aButton.menu = UIMenu(children: ele + [trick])也能正常执行,但ele.append(contentsOf: [trick])还是失败,强制转换trick as! UIAction也提示类型不相关。请问该现象的技术原因是什么?

补充:通常创建UIAction数组的方式如下:

let noms = [
    ("TAG", "Do crazy things", "arrowtriangle.right.and.line.vertical.and.arrowtriangle.left"),
    ("BLAH", "Even more\nwild stuff.", "rectangle.grid.3x2"),
    ("LOUT", "Logout now", "lock.open")
]

let ele = noms.map({ fn in
    return UIAction(title: fn.1, image: UIImage(systemName: fn.2)) { [weak self] _ in
        guard let self else { return }
        aButtonProcess(fn.0)
    }
})

技术原因分析

核心原因是Swift强类型特性下的容器类型约束差异:

  • 数组ele的类型是严格的[UIAction]
    你通过map生成的ele是明确的UIAction专属数组,Swift作为强类型语言,要求数组内的元素必须完全匹配定义的类型。UIDeferredMenuElement和UIAction是毫无继承/兼容关系的独立类型,所以直接追加必然触发类型不匹配错误,强制转换也不可能生效——两者根本不在同一个类型分支上。

  • UIMenu的children参数接收的是[UIMenuElement]
    实际上UIAction和UIDeferredMenuElement都属于UIMenuElement的子类(准确说是遵循UIMenuElement协议的类型)。当你写出[ele[0], trick]或者ele + [trick]时,Swift会自动将这个临时数组的类型推断为[UIMenuElement],刚好符合UIMenu初始化方法的参数要求,因此可以正常运行。

总结来说:你的ele是只能装UIAction的“专用容器”,而UIMenu的children是能装所有UIMenuElement子类的“通用容器”,两者的类型约束不同,才导致了这种看似矛盾的现象。


内容的提问来源于stack exchange,提问作者Fattie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:16:17