NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

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!

   

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.

1      

Hacking with Swift is sponsored by Instabug

SPONSORED Catch bugs as soon as they happen and know exactly why a crash occurred. Instabug's SDK grabs all the logs they need to fix bugs, crashes and performance issues in minutes instead of days. Get screenshots, device details, network logs, repro steps, and tons of other critical insights needed to resolve issues and prioritize product backlogs straight from your dashboard. It only takes a minute to integrate!

Get started now

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

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.