UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Problem with passing Data around

Forums > SwiftUI

@LilaQ  

Hi guys,

I'm pretty new to Swift and SwiftUI, and I've read a lot, but I'm currently facing a problem where I'm not sure what is the best way to pass data around. I tried to break it into some simple sample code, so you can see where my issue is:

class MyClass: ObservableObject, Identifiable {

    let objectWillChange = PassthroughSubject<MyClass, Never>()

    var name: String = "" {
        didSet {
            objectWillChange.send(self)
        }
    }
    var image: String = "" {
        didSet {
            objectWillChange.send(self)
        }
    }

    init(withName: String, withImage: String) {
        name = withName
        image = withImage
    }

}

class WrapperClass: ObservableObject {

    let objectWillChange = PassthroughSubject<WrapperClass, Never>()

    var id: Int = 0 {
        didSet {
            objectWillChange.send(self)
        }
    }

    var objects: [MyClass] = [] {
        didSet {
            objectWillChange.send(self)
        }
    }

    init(withId: Int, withObjects: [MyClass]) {
        id = withId
        objects = withObjects
    }

}

struct ContentView: View {
    var wrapper = WrapperClass(withId: 0, withObjects: [
        MyClass(withName: "a", withImage: "a_img"),
        MyClass(withName: "b", withImage: "b_img")
    ])

    var body: some View {
        VStack {
            Top()
                .frame(height: 200)
                .background(Color.blue)
            Bottom()
                .frame(height: 200)
                .background(Color.red)
        }.environmentObject(wrapper)
    }
}

struct Top:View {
    var body: some View {
        Text("Top")
          //this is where I need the object that was tapped in Bottom so I can display it and modify it directly
    }
}

struct Bottom:View {
    @EnvironmentObject var wrapper: WrapperClass
    var body: some View {
        List {
            ForEach(wrapper.objects) { obj in
                HStack {
                    Text(obj.name)
                    Text(obj.image)
                }.onTapGesture {
                    print("Pass to top to display and modify the data of this object")
                      //Pass this object to Top view here on tap, so it can be displayed and modified there
                }
            }
        }
    }
}

As you can see, I have an array of objects of a custom class, which I pass to the bottom view, and display them in a list. Now, I want to be able to tap on the list items, so the object gets passed to the top view, where I can then modifiy it, and represent the changes in the list in bottom view immediately.

I hope I was able to make the problem somewhat clear. I really hope someone can point me in the right direction how to handle something like this.

Thanks a lot in advance! This site is awesome!

Cheers!

3      

Try this:

class MyClass: ObservableObject, Identifiable {

    @Published var name: String = ""

    @Published var image: String = ""

    init(withName: String, withImage: String) {
        name = withName
        image = withImage
    }

}

class WrapperClass: ObservableObject {

    @Published var id: Int = 0

    @Published var objects: [MyClass] = []

    @Published var selectedObject: MyClass? = nil

    init(withId: Int, withObjects: [MyClass]) {
        id = withId
        objects = withObjects
    }

}

struct ContentView: View {
    @StateObject var wrapper = WrapperClass(withId: 0, withObjects: [
        MyClass(withName: "a", withImage: "a_img"),
        MyClass(withName: "b", withImage: "b_img")
    ])

    var body: some View {
        VStack {
            Top()
                .frame(height: 200)
                .background(Color.blue)
            Bottom()
                .frame(height: 200)
                .background(Color.red)
        }.environmentObject(wrapper)
    }
}

struct Top:View {
    @EnvironmentObject var wrapper: WrapperClass

    var body: some View {
        Text(wrapper.selectedObject?.name ?? "No object")
        //this is where I need the object that was tapped in Bottom so I can display it and modify it directly
    }
}

struct Bottom:View {
    @EnvironmentObject var wrapper: WrapperClass

    var body: some View {
        List {
            ForEach(wrapper.objects) { obj in
                HStack {
                    Text(obj.name)
                    Text(obj.image)
                }.onTapGesture {
                    print("Pass to top to display and modify the data of this object")
                    //Pass this object to Top view here on tap, so it can be displayed and modified there
                    wrapper.selectedObject = obj
                }
            }
        }
    }
}

Note: You don't need to do this kind of stuff in your ObservableObjects:

    let objectWillChange = PassthroughSubject<MyClass, Never>()

    var name: String = "" {
        didSet {
            objectWillChange.send(self)
        }
    }
    var image: String = "" {
        didSet {
            objectWillChange.send(self)
        }
    }

Just use the @Published property wrapper.

4      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.