简体   繁体   中英

Sharing Data between Views in Swift/better approach for this?

I am brand new to Swift and SwiftUi, decided to pick it up for fun over the summer to put on my resume. As a college student, my first idea to get me started was a Check calculator to find out what each person on the check owes the person who paid. Right now I have an intro screen and then a new view to a text box to add the names of the people that ordered off the check. I stored the names in an array and wanted to next do a new view that asks for-each person that was added, what was their personal total? I am struggling with sharing data between different structs and such. Any help would be greatly appreciated, maybe there is a better approach without multiple views? Anyways, here is my code (spacing a little off cause of copy and paste):

    import SwiftUI

struct ContentView: View {
    
    var body: some View {
        
        NavigationView {
            
            ZStack {
                
                Image("RestaurantPhoto1").ignoresSafeArea()
                
                VStack {
                    
                    Text("TabCalculator")
                        
                        .font(.largeTitle)
                        
                        .fontWeight(.bold)
                        
                        .foregroundColor(Color.white)
                        
                        .multilineTextAlignment(.center)
                        
                        .padding(.bottom, 150.0)
                    
                    
                    
                    NavigationLink(
                        
                        destination: Page2(),
                        
                        label: {
                            
                            Text("Get Started!").font(.largeTitle).foregroundColor(Color.white).padding().background(/*@START_MENU_TOKEN@*//*@PLACEHOLDER=View@*/Color.blue/*@END_MENU_TOKEN@*/)
                            
                        })
                }
                
            }
            
        }
        
    }
    
}



struct Page2: View {
    
    @State var nameArray = [String]()
    
    @State var name: String = ""
    
    @State var numberOfPeople = 0
    
    @State var personTotal = 0
    
    var body: some View {
        
        NavigationView {
            
            VStack {
                
                TextField("Enter name", text: $name, onCommit: addName).textFieldStyle(RoundedBorderTextFieldStyle()).padding()
                List(nameArray, id: \.self) {
                    Text($0)
                }
            }
            
            .navigationBarTitle("Group")
        }
    }
    
    func addName() {
        
        let newName = name.capitalized.trimmingCharacters(in: .whitespacesAndNewlines)
        guard newName.count > 0 else {
            
            return
            
        }
        nameArray.append(newName)
        name = ""
        
    }
}


struct ContentView_Previews: PreviewProvider {
    
    static var previews: some View {
        
        Group {
            
            ContentView()
            ContentView()
            
        }
    }
}

You have multiple level for passing data between views in SwiftUI. Each one has its best use cases.

  • Static init properties
  • Binding properties
  • Environment Objects

Static init properties. You're probably used to that, it's just passing constants through your view init function like this:

struct MyView: View {
    var body: some View {
        MyView2(title: "Hello, world!")
    }
}

struct MyView2: View {
    let title: String
    var body: some View {
        Text(title)
    }
}

Binding properties. These enables you to pass data between a parent view and child. Parent can pass the value to the child on initialization and updates of this value and child view can update the value itself (which receives too).

struct MyView: View {
    // State properties stored locally to MyView
    @State private var title: String

    var body: some View {
        // Points the MyView2's "title" binding property to the local title state property using "$" sign in front of the property name.
        MyView2(title: $title)
    }
}

struct MyView2: View {
    @Binding var title: String
    var body: some View {
        // Textfield presents the same value as it is stored in MyView.
        // It also can update the title according to what the user entered with keyboard (which updates the value stored in MyView.
        TextField("My title field", text: $title)
    }
}

Environment Objects. Those works in the same idea as Binding properties but the difference is: it passes the value globally through all children views. However, the property is to be an "ObservableObject" which comes from the Apple Combine API. It works like this:

// Your observable object
class MyViewManager: ObservableObject {
    @Published var title: String

    init(title: String) {
        self.title = title
    }
}

struct MyView: View {
    // Store your Observable object in the parent View
    @StateObject var manager = MyViewManager(title: "")

    var body: some View {
        MyView2()
            // Pass the manager to MyView2 and its children
            .environmentObject(manager)
    }
}

struct MyView2: View {
    // Read and Write access to parent environment object
    @EnvironmentObject var manager: MyViewManager

    var body: some View {
        VStack {
            // Read and write to the manager title property
            TextField("My title field", text: $manager.title)
            MyView3()
                // .environmentObject(manager)
                // No need to pass the environment object again, it is passed by inheritance.
        }
    }
}

struct MyView3: View {
    @EnvironmentObject var manager: MyViewManager

    var body: some View {
        TextField("My View 3 title field", text: $manager.title)
    }
}

Hope it was helpful. If it is, don't forget to mark this answer as the right one

For others that are reading this to get a better understanding, don't forget to upvote by clicking on the arrow up icon

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM