英文:
How to programmatically invoke the action of a `UISwitch`?
问题
我有一个UIViewController
,位于一个SPM包中,其中包含一个带有一些简单单元格的UITableView
- 这些单元格要么是详细披露,要么有一个UISwitch
。
我正在尝试编写单元测试,以确认当特定行中的开关被切换时,会调用所需的操作。该操作是由其他代码提供的,因此单元格配置如下:
let toggle = UISwitch(frame: .zero, primaryAction: UIAction(handler: { action in
guard let toggle = action.sender as? UISwitch else { return }
toggleAction(toggle.isOn)
}))
cell.accessoryView = toggle
(其中toggleAction
是传递给VC的init
的众多操作之一)
我的测试可以找到感兴趣的行以及其中的开关。它可以通过.isOn
修改值,但这不会触发操作。我知道需要一个UIApplication
才能使.sendActions(for:)
起作用,因此我使用了这里的解决方案,并确认它对UIButton
有效。我尝试发送各种事件给UISwitch
(.touchUpInside
,.valueChanged
,.primaryActionTriggered
),但它们都不会导致注册的操作被调用。这是否可能?
英文:
I have a UIViewController
, in an SPM package, with a UITableView
with some simple cells - they're either detail disclosures or have a UISwitch
.
I'm trying to write unit tests to confirm that when the switch in a specific row is toggled, the desired action is invoked. That action was provided by other code, so the cell configuration looks like:
let toggle = UISwitch(frame: .zero, primaryAction: UIAction(handler: { action in
guard let toggle = action.sender as? UISwitch else { return }
toggleAction(toggle.isOn)
}))
cell.accessoryView = toggle
(where toggleAction
was one of many passed to the VC's init
)
My test can find the row of interest, and the switch on it. It can modify the value via .isOn
, but that doesn't trigger the action. I am aware of the need for a UIApplication
in order for .sendActions(for:)
to work, so am using the solution here, and confirm that it works for UIButton
s. I have tried sending various events to the UISwitch
(.touchUpInside
, .valueChanged
, .primaryActionTriggered
), but none of them cause the registered action to be invoked. Is it possible?
答案1
得分: 1
UISwitch
是一个 UIControl
。由于你使用了一个 UIAction
来设置开关的主要动作,你可以在开关上调用 sendActions
:
let switch = ... // 从表格单元格获取 UISwitch 的引用
switch.isOn = true // 根据需要设置为 true 或 false
switch.sendActions(for: .primaryActionTriggered)
这将导致调用开关的动作,进而调用你的 toggleAction
方法。
这不需要引用 UIApplication
。
英文:
UISwitch
is a UIControl
. Since you setup the switch with a UIAction
for the primary action, you can call sendActions
on the switch:
let switch = ... // a reference to the UISwitch from the table cell
switch.isOn = true // or false as needed
switch.sendActions(for: .primaryActionTriggered)
This will result in the switch's action being called which in turn calls your toggleAction
method.
No reference to the UIApplication
is needed for this.
Here is some sample code that demonstrates that using sendActions
works for both UISwitch
and UIButton
and that it works whether the control is setup with a primary action or with a target/selector.
The following can be run in an iOS Swift Playground.
class Controls {
func toggleAction(_ isOn: Bool) {
print("toggleAction: \(isOn)")
}
@objc func toggleHandler(_ sender: UIControl) {
print("toggleHandler: \(sender)")
}
lazy var toggle = UISwitch(frame: .zero, primaryAction: UIAction(handler: { action in
guard let toggle = action.sender as? UISwitch else { return }
self.toggleAction(toggle.isOn)
}))
lazy var button = UIButton(primaryAction: UIAction(handler: { action in
self.toggleAction(false)
}))
lazy var other = UIButton(type: .custom)
func doStuff() {
other.addTarget(self, action: #selector(toggleHandler), for: .touchUpInside)
toggle.isOn.toggle()
toggle.sendActions(for: .primaryActionTriggered)
other.sendActions(for: .touchUpInside)
button.sendActions(for: .primaryActionTriggered)
}
}
let x = Controls()
x.doStuff()
The output will be something like:
>toggleAction: true
toggleHandler: <UIButton: 0x7fb77f406320; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x6000037e2fc0>>
toggleAction: false
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论