iOS Combine Framework-发布者仅发布一次,然后不再发布

时间:2020-03-20 19:46:23

标签: ios swift reactive-programming combine

我正在尝试将iOS 13 Combine框架与某些UIKit控件结合使用。我想设置一个包含一个开关的ViewController,每当开关打开/关闭时,该开关就会启用/禁用一个按钮。根据Apple的文档,UIKit控件具有对Combine发行者等的内置支持,因此应该可行。

我有一个包含UISwitch和UIButton的viewcontroller,如下所示:

link to screenshot of my viewcontroller

这是我的代码:

import Combine
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var mySwitch: UISwitch!
    @IBOutlet weak var myButton: UIButton!

    var myCancellable: AnyCancellable?

    override func viewDidLoad() {
        super.viewDidLoad()

        mySwitch.isOn = true // Set initial state of switch

        myButton.setTitle("Enabled", for: .normal)
        myButton.setTitle("Disabled", for: .disabled)

        myCancellable = mySwitch.publisher(for: \.isOn)
                                .subscribe(on: RunLoop.main)
                                .assign(to: \.isEnabled, on: myButton)
    }
}

上述代码应该(或者我认为)每当该属性更改时就发出开关的.isOn属性的值,并将该值分配给按钮的.isEnabled属性。如果它按照我期望的方式运行,则意味着在将开关切换到ON时,按钮标题应显示为“ Enabled”,并且应该启用该按钮。将UISwitch切换为OFF时,按钮标题应显示为“ Disabled”,并且按钮应被禁用。

但是它并没有达到我的期望。首次在viewDidLoad()中设置发布者的值时,开关的发布者的值仅发出一次。轻按开关以将其打开或关闭时,它永远不会再发出值。我可以说它至少发出一次该值,因为如果我将开关的初始状态更改为打开或关闭,则在加载视图控制器时,按钮将设置为预期状态。

通常情况下,您应该保持对发布者的强烈引用,否则发布者/订阅者将立即终止,因此这就是为什么我持有带有myCancellable变量的引用的原因。但这不能解决问题,点击开关时仍不会发出值。

有人对如何解决此问题有任何想法吗?看来这应该是使用Combine的简单“ Hello World”类型示例,我不知道我在这里缺少什么。

1 个答案:

答案 0 :(得分:2)

一个常见的错误是认为UISwitch的{​​{1}}属性符合KVO。 Sadly, it isn't.您不能使用isOn来观察它。

publisher(for:)中创建一个@IBAction,然后将开关的Value Change事件连接到该事件。