Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't my SwiftUI Text view update when viewModel changes using Combine?

I'm creating a new watchOS app using SwiftUI and Combine trying to use a MVVM architecture, but when my viewModel changes, I can't seem to get a Text view to update in my View.

I'm using watchOS 6, SwiftUI and Combine. I am using @ObservedObject and @Published when I believe they should be used, but changes aren't reflected like I would expect.

// Simple ContentView that will push the next view on the navigation stack
struct ContentView: View {
    var body: some View {
        NavigationLink(destination: NewView()) {
            Text("Click Here")
        }
    }
}

struct NewView: View {
    @ObservedObject var viewModel: ViewModel

    init() {
        viewModel = ViewModel()
    }

    var body: some View {
        // This value never updates
        Text(viewModel.str)
    }
}

class ViewModel: NSObject, ObservableObject {
    @Published var str = ""
    var count = 0

    override init() {
        super.init()

        // Just something that will cause a property to update in the viewModel
        Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            self?.count += 1
            self?.str = "\(String(describing: self?.count))"

            print("Updated count: \(String(describing: self?.count))")
        }
    }
}

Text(viewModel.str) never updates, even though the viewModel is incrementing a new value ever 1.0s. I have tried objectWillChange.send() when the property updates, but nothing works.

Am I doing something completely wrong?

like image 569
lepolt Avatar asked Oct 04 '19 01:10

lepolt


1 Answers

For the time being, there is a solution that I luckily found out just by experimenting. I'm yet to find out what the actual reason behind this. Until then, you just don't inherit from NSObject and everything should work fine.

class ViewModel: ObservableObject {
    @Published var str = ""
    var count = 0

    init() {

        // Just something that will cause a property to update in the viewModel
        Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            self?.count += 1
            self?.str = "\(String(describing: self?.count))"

            print("Updated count: \(String(describing: self?.count))")
        }
    }
}

I've tested this and it works.


A similar question also addresses this issue of the publisher object being a subclass of NSObject. So you may need to rethink if you really need an NSObject subclass or not. If you can't get away from NSObject, I recommend you try one of the solutions from the linked question.

like image 70
nayem Avatar answered Oct 12 '22 09:10

nayem