简体   繁体   中英

iOS Combine Framework - Publisher Only Publishes Once and Then Never Again

I am trying to use the iOS 13 Combine framework in conjunction with some UIKit controls. I want to set up a viewcontroller that contains a switch that enables/disables a button whenever the switch is toggled on/off. According to Apple's documentation, UIKit controls have built-in support for Combine publishers, etc. so this should be possible.

I have a viewcontroller that contains a UISwitch and a UIButton, as shown here:

link to screenshot of my viewcontroller

and here is my code:

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)
    }
}

The above code should (or so I thought) emit the value of the switch's .isOn property, whenever that property changes, and assign the value to the button's .isEnabled property. If it is running the way I would expect, that means that when the switch is toggled ON the button title should read "Enabled" and the button should be enabled. When the UISwitch is toggled OFF, then the button title should read "Disabled" and the button should be disabled.

But it does not behave the way I am expecting. The value from the switch's publisher is only emitted once, when the publisher is first set up inside viewDidLoad() . When tapping on the switch to toggle it on or off, it never emits a value ever again. I can tell it is at least emitting the value once, because if I change the initial state of the switch to either on or off, the button is set to the expected state when the viewcontroller is loaded.

Typically you are supposed to keep a strong reference to the publisher, or else the publisher/subscriber will be terminated immediately, so that's why I am holding a reference with the myCancellable variable. But this does not fix the issue, the values are still not emitted when tapping on the switch.

Does anyone have any ideas on how to fix this? This seems like it should be a simple "Hello World" type of example using Combine, and I don't know what I am missing here.

A common mistake is thinking that UISwitch 's isOn property is KVO-compliant. Sadly, it isn't. You cannot use publisher(for:) to observe it.

Create an @IBAction in your ViewController , and connect the switch's Value Changed event to it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM