Jasper
Jasper

Reputation: 3

ForEach loop inside a button action in SwiftUI?

I understand that a ForEach loop is typically used to display a view. When I put a ForEach loop inside the action button it pretty much tells me Button action cannot conform to the view protocol. So how can I use a loop to make the button carry out multiple actions?

struct SomeView: View {
    var newExercises = [NewExercise]()
    var finalExercises = [Exercise]()

    var body: some View {
        Button(action: {
            ForEach(newExercises) { newExercise in
                //.getExercise() returns an Exercise object
                finalExercises.append(newExercise.getExercise())
            }

        }) {
            Text("Done")
        }
    }
}

I want the button to add an Exercise (by calling .getExercise()) to the finalExercises array for each newExercise in the newExercises array.

How can I go about doing this?

Upvotes: 0

Views: 2055

Answers (1)

joseph0x4365732E
joseph0x4365732E

Reputation: 151

The new SwiftUI ForEach statement returns a View for each Element of an Array. For your code, you simply need to run a Void, Array<Exercise>.append(newElement: Exercise) not get multiple View's, so you can use a for loop, map, or Array.forEach(body: (_) throws -> Void).

If the order in which the newExercises are appended matters, the most elegant solution will be mapping each NewExercise of finalExercises to a Exercise, and appending the resulting Array<Exercise>, with Array<Exercise>.append(contentsOf: Sequence).

struct SomeView: View {
    @State var newExercises = [NewExercise]()
    @State var finalExercises = [Exercise]()

    var body: some View {
        Button(action: {
            self.finalExercises.append(contentsOf:
                self.newExercises.map { newExercise -> Exercise in
                    newExercise.getExercise()
                }
            )


        }) {
            Text("Done")
        }
    }
}

If the order in which the newExercises are appended does not matter, you can call Array<Exercise>.append(newElement: Exercise) from newExcercises.forEach, which is different than a SwiftUI ForEach statement:

struct SomeView: View {
    @State var newExercises = [NewExercise]()
    @State var finalExercises = [Exercise]()

    var body: some View {
        Button(action: {
            self.newExercises.forEach { newExercise in
                self.finalExercises.append(newExercise.getExercise())
            }
        }) {
            Text("Done")
        }
    }
}

The way to complete what you want with a for loop would be simple, but less elegant:

struct SomeView: View {
    @State var newExercises = [NewExercise]()
    @State var finalExercises = [Exercise]()

    var body: some View {
        Button(action: {
            for newExercise in self.newExercises {
                self.finalExercises.append(newExercise.getExercise())
            }

        }) {
            Text("Done")
        }
    }
}

Upvotes: 1

Related Questions