I'm trying to dynamically update a reference to an @Published var
, but I'm not sure how to do it. Returning the value only is just a bool value and loses it's reference to the publisher and doesn't work. I tried returning the publisher itself ($self.isBig
) but I can't seem to figure out how to update the value once I have the publisher instead of the @Published property.
I'm basically just trying to treat an @Published
as a reference and update the reference on the class instead of copying the publisher's value.
This is a contrived example just trying to get the point across, what I want to do is:
import UIKit
import Combine
class MyClass {
struct MyData {
enum MyDataType {
case big
case yellow
case bird
}
var type: MyDataType
var isEnabled: Bool
}
private var cancellables = Set<AnyCancellable>()
@Published var isBig: Bool = false
@Published var isYellow: Bool = false
@Published var isBird: Bool = false
var mySwitch = UISwitch()
init() {
// Add mySwitch and setupSubscribers...
}
func updatePublishers(from data: MyData) {
let publisherForData = specificPublisherForData(data)
// I want to access the underlying value for the @Published and set it here
// publisherForData = data.isEnabled
}
func specificPublisherForData(_ data: MyData) -> Published<Bool>.Publisher {
switch data.type {
case .big: return self.$isBig
case .yellow: return self.$isYellow
case .bird: return self.$isBird
}
}
func setupSubscribers() {
$isBig.sink { [weak self] isBig in
guard let self = self else { return }
self.mySwitch.isOn = isBig
}.store(in: &cancellables)
// ... add subscribers for the other ones
}
}
It looks like you're trying to assign a new value to the Publisher
in updatePublishers
, but that's not really how @Publisher
s work -- they're just broadcasting values.
Instead, it seems like using a key path might be what you're after:
class MyClass {
struct MyData {
enum MyDataType {
case big
case yellow
case bird
}
var type: MyDataType
var isEnabled: Bool
}
private var cancellables = Set<AnyCancellable>()
@Published var isBig: Bool = false
@Published var isYellow: Bool = false
@Published var isBird: Bool = false
var mySwitch = UISwitch()
init() {
// Add mySwitch and setupSubscribers...
}
func updatePublishers(from data: MyData) {
let keypath = specificKeypathForData(data)
self[keyPath: keypath] = data.isEnabled
}
func specificKeypathForData(_ data: MyData) -> ReferenceWritableKeyPath<MyClass,Bool> {
switch data.type {
case .big: return \.isBig
case .yellow: return \.isYellow
case .bird: return \.isBird
}
}
func setupSubscribers() {
$isBig.sink { [weak self] isBig in
guard let self = self else { return }
self.mySwitch.isOn = isBig
}.store(in: &cancellables)
// ... add subscribers for the other ones
}
}
In a playground:
var myClass = MyClass()
myClass.setupSubscribers()
var data = MyClass.MyData(type: .big, isEnabled: true)
myClass.updatePublishers(from: data)
print(myClass.isBig)
Yields:
true