Home > Net >  Get reference for an @Published that can update the value
Get reference for an @Published that can update the value

Time:01-15

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

CodePudding user response:

It looks like you're trying to assign a new value to the Publisher in updatePublishers, but that's not really how @Publishers 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

  •  Tags:  
  • Related