How to access content view's elements later in SwiftUI?

Viewed 2372

Let's say that I have a content view like this one:

struct ContentView: View {
    @State private var selection = 0

    var body: some View {
        TabView(selection: $selection) {
            CustomClass()
                .tabItem {
                    VStack {
                        Image("First")
                        Text("First")
                    }
                }
                .tag(0)
            Button(action: { EmployeeStorage.sharedInstance.reload() }) {
                Text("Reload")
            }
                .tabItem {
                    VStack {
                        Image("Second")
                        Text("Second")
                    }
                }
                .tag(1)
        }
    }
}

// MARK: - SomeDelegateThatUpdatesMeLater
extension ContentView: SomeDelegateThatUpdatesMeLater {
    func callback() {
        // Here I want to update my content view's subviews
        // The ContentClass instance needs to be updated
    }
}

Let's say that I want to listen to a callback method and then update the content view's tab number 1 (CustomClass) later on. How to access the content view's subviews? I'd need something like UIKit's subviewWithTag(_:). Is there any equivalent in SwiftUI?

1 Answers

You should probably rethink your approach. What exactly is it you want to happen? You have some external data model type that fetches (or updates) data and you want your views to react to that? If that's the case, create an ObservableObject and pass that to your CustomClass.

struct CustomClass: View {

   @ObservedObject var model: Model

   var body: some View {
      // base your view on your observed-object
   }
}

Perhaps you want to be notified of events that originate from CustomClass?

struct CustomClass: View {

  var onButtonPress: () -> Void = { }

  var body: some View {
    Button("Press me") { self.onButtonPress() }
  }
}

struct ParentView: View {

  var body: some View { 
    CustomClass(onButtonPress: { /* react to the press here */ })
  }
}

Lastly, if you truly want some kind of tag on your views, you can leverage the Preferences system in SwiftUI. This is a more complicated topic so I will just point out what I have found to be a great resource here: https://swiftui-lab.com/communicating-with-the-view-tree-part-1/

Related