0

I'm developing a simple SwiftUI app in Xcode 11. I want to have a form that loops through multiple user input strings and displays a form with a button. When the user presses the button it modifies the input value - specifically increment or decrement it.

However when passing an array of references like UserInput().foo where UserInput is a published observable object I cannot modify the value inside a ForEach because the ForEach is passed a copy as oppose to the original reference (at least that's my basic understanding). How do I then try to achieve it? I read about inout and everybody says to avoid it but surely this must be a relatively common issue.

I've made an simple example of what I'm trying to do but I can't quite work it out:

import SwiftUI

class UserInput: ObservableObject {
    @Published var foo: String = ""
    @Published var bar: String = ""
}
struct ContentView: View {
    
    @ObservedObject var input = UserInput()
    
    var body: some View {
        LoopInputs()
    }
    func LoopInputs() -> AnyView?{
        
        var userinputs = [
            [UserInput().foo, "Foo"],
            [UserInput().bar, "Bar"]
        ]
        
        var inputs: some View{
            VStack(){
                ForEach(userinputs, id: \.self){userinput in
                    Text("\(userinput[1]): \(String(userinput[0]))")
                    Button(action: {
                        increment(input: String(userinput[0]))
                    }){
                        Text("Increase")
                    }
                }
            }
        }
        
        return AnyView(inputs)
    }
    func increment(input: String){
        var lead = Int(input) ?? 0
        lead += 1
        //    input = String(lead)
    }
}
1
  • I can't catch sense of this snapshot, it does not operate with var input at all. Would you elaborate more? Commented Jul 4, 2020 at 9:03

1 Answer 1

0

As I understood, when adding a value to userinputs, the ForEach values doesn't change. Well, if that's the case, first of all, you could try creating a struct and in it, you declare foo and bar, then just declare a variable of type the struct. It'll look like this:

struct Input: Identifiable {
    var id = UUID()
    var foo: String
    var bar: String
}
class UserInput: ObservableObject {
    @Published var inputs: [Input] = [Input]()
}
//ContentView
struct ContentView: View {
    @ObservedObject var input = UserInput()
    var body: some View {
        LoopInputs()
    }
    func LoopInputs() -> AnyView? {
        var inputs: some View {
            VStack {
                ForEach(input.inputs) { userinput in
                    Text("\(userinput.bar): \(String(userinput.foo))")
                    Button(action: {
                        increment(input: String(userinput.foo))
                    }) {
                        Text("Increase")
                    }
                }
            }
        }
        return AnyView(inputs)
    }
    func increment(input: String) {
        var lead = Int(input) ?? 0
        lead += 1
    //    input = String(lead)
    }
}

Wouldn't this be easier and more elegant?

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.