WWDC21 SALE: Save 50% on all my Swift books and bundles! >>

Calling Functions of Sub-views

Forums > SwiftUI

My question is essentially this: if I have a view DetailView within another view MainView, how can I call a function of DetailView from MainView? Here's a simple example of what I'm trying to acheive:

struct MainView: View {    
    var body: some View {
        VStack {
            Button("Increase Count") {
                // Call 'stepCount'
            }
            DetailView()
        }
    }
}

struct DetailView: View {
    @State private var count = 0
    var body: some View {
        Text("The count is: \(self.count)")
    }
    func stepCount() {
        count += 1
    }
}

I'd like stepCount() to be called whenever the button is pressed. Clearly, I could just move the button inside DetailView, but in more complex projects this isn't always practical.

Here is one idea I had that doesn't work, but I thought it might be worth sharing it anyway:

struct MainView: View {
    var detail : DetailView = DetailView()
    var body: some View {
        VStack {
            Button("Increase Count") {
                self.detail.stepCount()
            }
            detail
        }
    }
}

I've found through print statements that the stepCount function is performed when the button is pressed, but the text in DetailView doesn't change.

I'd be hugely grateful if anyone could suggest a solution, and also if anyone could explain why the idea above doesn't work!

   

You wouldn't call a DetailView function from MainView.

You would instead use some combination of bindings and/or environment objects to update a value shared between the two views.

   

struct MainView: View {
    @State
    private var count: Int = 0
    var body: some View {
        VStack {
            Button("Increase Count") {
                // Call 'stepCount'
                count += 1
            }
            DetailView(count: $count)
        }
    }
}

struct DetailView: View {
    @Binding
    var count: Int
    var body: some View {
        Text("The count is: \(self.count)")
    }
//    func stepCount() {
//        count += 1
//    }
}

   

You really only need the @Binding in DetailView if count can be changed inDetailView and the changed value then fed back up to MainView. Otherwise, simply passing in the value of count would suffice.

struct MainView: View {
    @State
    private var count: Int = 0
    var body: some View {
        VStack {
            Button("Increase Count") {
                self.count += 1
            }
            DetailView(count: count)
        }
    }
}

struct DetailView: View {
    let count: Int

    var body: some View {
        Text("The count is: \(count)")
    }
}

Because whenever count is updated in MainView, the DetailView will get redrawn with the new value anyway.

   

Save money with our WWDC sale!

SAVE 50% To celebrate WWDC21, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.