1
votes

I would like to display a Text (view) in SwiftUI, that has mutable String content.

@State var myvar : String = "Undefined"
var body: some view {
Text("Content: \(myvar)")
}

func abc() {
self.myvar = "Defined"
}

Whenever I call the abc() function, the value of myvar doesn't get updated. I have checked this using a debugPrint(self.myvar) in abc().

This code is inside my ContentView.swift, while I am calling contentView.abc() from HostingController.swift in a delegate callback method.

Is there a solution to create mutable/changeable Strings for this "external" use in SwiftUI?

EDIT:

From HostingController:

override var body: ContentView {
let contentView = ContentView().environmentObject(contentModel)
...
return contentView 

The last line gives the error ´Cannot convert return expression of type some View to return type ContentView´. It is to note, that I am working in a WatchKit context, so this is an Apple Watch Application.

1
It should work, and actually does. Can you show how you call abc()? (I feel the reason is in it) - Asperi
@Asperi Thanks for the reply! This code is inside my ContentView.swift, while I am calling contentView.abc() from HostingController.swift in a delegate callback method. - Florian S
This is it - you can change @State only within View itself. - Asperi
How do I go about this then, @Asperi ? I would like to change it from the HostingController, because that class holds the logic to call abc(). Any idea? - Florian S
Yes, see the answer. - Asperi

1 Answers

1
votes

It is possible to do via environmentObject

Create view model class to hold myvar state

class ViewModel: ObservableObject {
    @Published var myvar: String = "Undefined"
}

Declare it as member of SceneDelegate

let contentModel = ViewModel()

Pass it to content view before adding to hosting controller

let contentView = ContentView().environmentObject(contentModel)

Change in other scene delegate (or other place passed by reference)

self.contentModel.myvar = "Defined"

Use in ContentView

struct ContentView: View {
    @EnvironmentObject var viewModel: ViewModel

    var body: some view {
        Text("Content: \(viewModel.myvar)")
    }
    ...