2

I am having troubles with running view methods on published property value change. My playground sample code looks like this:

class MyFoo: ObservableObject {
    @Published var bar: String
    init(bar: String) {
        self.bar = bar
    }

    func setNewText(newString: String) {
        self.bar = newString
    }

    func runFunctions() {
        setNewText(newString: "Test")
    }
}

struct TestView: View {
    @ObservedObject let foo = MyFoo(bar: "bar0")

    init(){
        let barSink = foo.$bar
            .sink() { //THIS IS WHERE I GET ERROR "Escaping closure captures mutating 'self' parameter"
                self.printResult(result: $0)
            }
    }

    func printResult(result: String) {
        print(result)
    }
}

let a = TestView()

Basically I know why I get this error in closure but I don't know how to go around it. Is this the right approach for running view methods on VM published property value changed?

I need this because I am using custom spinner that is not SwiftUI ready so I cant bind to it, and the only way to show/hide it is by calling its methods.

Any help would be most appreciated

2
  • try adding @ObservedObject before let foo = MyFoo(bar: "bar0") and make MyFoo inherit from ObservableObject: class MyFoo: ObservableObject {} Commented Nov 21, 2019 at 14:56
  • I have edited the question, but it doesn't fix the error Commented Nov 21, 2019 at 15:17

1 Answer 1

5

I don't know how the playground works but I try to answer you question. I tested the code in the simulator and on a real device:


class MyFoo: ObservableObject {
    @Published var bar: String
    init(bar: String) {
        self.bar = bar
    }

    func setNewText(newString: String) {
        self.bar = newString
    }

    func runFunctions() {
        setNewText(newString: "Test")
    }


}

struct TestView: View {
    @ObservedObject var foo = MyFoo(bar: "bar0")

    var body: some View {
        Text("Lolz")
            .onReceive(self.foo.$bar, perform: { lolz in
                self.printResult(result: lolz)
            })
    }

    func printResult(result: String) {
        print(result)
    }

}

struct ContentView: View {
    var body: some View {
        TestView()
    }
}

The @ObservedObject needs to be a var. With onRecieve() you can listen to the publisher and update UI or call a function.

I hope this helps.

Sign up to request clarification or add additional context in comments.

4 Comments

Thx so much, don't know if this is official "Apple" solution, but it works like a charm!!!
Well onReceive() is specifically designed to listen to publisher! :)
Yeah I know, I was referring to adding Text block which will never be used as Text block, It would be a good idea to create custom control, say ActionBinder or something like that. ActionBinder() .onReceive(self.foo.$bar, perform: { p in self.runSomeAction(param: p) })
You can just make a custom View struct customView: View { var body: some View { Text("").onRecieve() }} and you can even do this in your parent and onReceive() on the customView

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.