从 IBAction 以编程方式设置 UISwitch isOn 再次调用 IBAction
Posted
技术标签:
【中文标题】从 IBAction 以编程方式设置 UISwitch isOn 再次调用 IBAction【英文标题】:Setting UISwitch isOn programmatically from IBAction calls IBAction again 【发布时间】:2017-03-03 22:17:46 【问题描述】:我刚刚注意到在其 IBAction 中设置 UISwitch 的 isOn
会导致再次调用 IBAction。所以下面的代码:
class ViewController: UIViewController
var count = 0
@IBOutlet weak var mySwitch: UISwitch!
override func viewDidAppear(_ animated: Bool)
super.viewDidAppear(animated)
mySwitch.isOn = false
@IBAction func buttonTapped(_ sender: UIButton)
mySwitch.isOn = !mySwitch.isOn
@IBAction func switchChanged(_ sender: UISwitch)
print("\(count) pre: \(mySwitch.isOn)")
mySwitch.isOn = !mySwitch.isOn
print("\(count) post: \(mySwitch.isOn)")
count += 1
当开关打开一次时打印以下内容:
0 pre: true
0 post: false
1 pre: false
1 post: true
-
开关在
viewDidLoad
中关闭
开关被用户打开
当switchChanged
(IBAction) 被调用时,开关现在打开
0 pre: true
已打印
开关在switchChanged
中以编程方式关闭
0 post: false
已打印
系统再次调用switchChanged
现在switchChanged
中的开关已关闭,并且调用了1 pre: false
以编程方式打开开关
1 post: true
已打印
为什么系统会第二次调用 IBAction?例如,当想要基于某种内部状态否定用户的操作时,如何解决这个问题?我觉得我遗漏了一些非常明显的东西,但我很确定类似的代码曾经可以工作。这是ios错误吗?它在 iOS 10.2 iPhone 5s 模拟器 Xcode 版本 8.2.1 (8C1002) 上运行
有趣的是,当点击绑定到buttonTapped
的按钮时(调用相同的方法),不会调用开关的 IBAction。
【问题讨论】:
您可能已将 switch 事件处理程序连接到两个不同的事件。 我对其进行了测试,并看到了与您相同的行为。仅当您通过点击它来更改开关时,通过拖动它来更改它只会导致该操作被调用一次。 在switchChanged
中切换开关没有意义。如果您希望开关关闭,请将其显式设置为关闭,然后再次调用该方法无关紧要,因为第二次它将关闭并且您将其设置为关闭并且不会被调用再次。
gnasher729,我确实考虑过不止一个事件可以连接到交换机,但事实并非如此。丹,我确认了您在拖动开关时看到的内容。即,通过拖动来更改开关,IBAction 被调用一次,“撤消”就像我最初预期的那样工作。
Paulw,如果我只是想让它关闭,也许这会奏效,但如果我真的想将它切换回初始状态怎么办,问题仍然在于为什么该方法被调用两次。此外,如果以编程方式设置 isOn 导致该方法被调用一次,为什么它不继续被调用?
【参考方案1】:
您的 IBAction 可能与 valueChanged
挂钩,这并不表示特定的触摸事件,只是它所说的值已更改。
我建议设置一个类似于var didOverrideSwitchValue = false
的变量,在设置新开关值之前将其设置为true
,然后在调用该函数时检查该变量。如果设置为true
,则设置为false
并返回。
或者,如果您希望仅在新设置打开时取消它,那么您可以执行 if (switch.isOn)
,如果需要,您可以通过关闭它来响应它。
【讨论】:
Andrew,没错,它已连接到valueChanged
。我不确定我是否完全理解您的第一个建议,假设我总是想切换布尔值。我仍在试图理解为什么 set-isOn/IBAction-invocation 循环不会无限期地继续,为什么拖动开关的行为与点击不同,以及为什么当 isOn
在 @ 中更改时开关的 IBAction 没有被调用987654329@.【参考方案2】:
我一直在与同样的问题作斗争并找到了解决方法...
在您的开关处理程序中检查发送方的“已选择”属性。我发现第一次是真的,第二次是假的,所以你可以判断你是否真的被用户操作调用了。
我猜想第二次触发事件的原因不是开关本身,或者可能在处理第一个事件后该属性被清除。也许 UIKit 大师可以插话。
-setOn:animated 的 UISwitch 文档:说
将开关设置到任一位置都不会导致发送操作消息。
看起来很清楚。感觉像是一个操作系统错误。
无论如何,这似乎可行,但它让我感到不安,因为我不完全理解为什么首先存在问题,也不确切为什么会修复它,我担心这两者都可能在未来的操作系统更新中发生变化。
更新
这在我的小测试应用程序中运行良好,但在我的实际应用程序中却不行,它具有更复杂的 UI 层次结构,带有导航栏、选项卡等。这只会加剧我对这个解决方案的不安。
【讨论】:
以上是关于从 IBAction 以编程方式设置 UISwitch isOn 再次调用 IBAction的主要内容,如果未能解决你的问题,请参考以下文章
UIButton click(IBAction)没有以编程方式触发
在 TableViewHeader 中以编程方式调用 IBAction