iSebbeYT
iSebbeYT

Reputation: 1521

SwiftUI ForEach does not compile with if block inside - Bug or am I doing something wrong?

I am getting an error that I don't understand. I am not sure if it is a compiler error or if I am doing something wrong?

Inside a swiftUI View I have a list showing elements from core data (Figure 1). In the example below I replaced the t.name with "yo" for some undefined reason 😅.

Anyway, the tasks is a fetch request from Core Data:

@FetchRequest(entity: Task.entity(), sortDescriptors: []) var tasks: FetchedResults<Task>

FIGURE 1: Works fine to build and run the app. enter image description here

FIGURE 2: Does not work to build and run the app. enter image description here

Please help me understand what I am doing wrong or is this a compiler bug? Why can't I add the if block inside the ForEach? I can provide more information if needed. Thanks!

Upvotes: 3

Views: 2161

Answers (4)

Simon
Simon

Reputation: 1860

What also worked for me was using a Group inside the ForEach like this:

ForEach(self.items, id: \.self { item in
   Group {
       if item.id == 0 {
           Text(String(item.id))
       }
   }
}

Upvotes: 1

Rhys Morgan
Rhys Morgan

Reputation: 123

For some reason, in the ForEach.init you're using, the view building closure isn't annotated with @ViewBuilder. This means that the if/else you're using is Swift's own if statement, not the SwiftUI construct which returns a _ConditionalContent.

I don't know if it's considered a bug by Apple, but I would definitely consider it to be one.

The easiest workaround is just to wrap the if/else in a Group - the Group.init is a @ViewBuilder, so will handle the if/else correctly.

Upvotes: 1

Alik
Alik

Reputation: 36

You have to return nil in case of a false condition. So you need to declare parameter as Optional and return nil in case of a false condition (XCode - 11.3.1).

ForEach(tasks, id: \.id) { t -> Text? in
    return condition ? Text("text") : nil
  }
}

Upvotes: 2

Asperi
Asperi

Reputation: 258057

You can use if inside ForEach, but you should remember that ForEach is not language operator foreach but a struct type with ViewBuilder in constructor with generics in declaration, so it needs to determine type, which in your case it cannot determine.

The possible solution is to tell explicitly which type you return, as below (tested with Xcode 11.2 / iOS 13.2)

ForEach(tasks, id: \.id) { name -> Text in
    if (true) {
        return Text("name")
    }
}

Upvotes: 4

Related Questions