0

In a swiftUI view that I'm writing, I need to use a ForEach, accessing each element of a list and its index. Most of the information I could find about this said to use .enumerated() as in ForEach(Array(values.enumerated()), id: \.offset) { index, value in }

However when I try to do that in my view:

/// A popover displaing a list of items.
struct ListPopover: View {
    // MARK: Properties
    /// The array of vales to display.
    var values: [String]
    
    /// Whether there are more values than the limit and they are concatenated.
    var valuesConcatenated: Bool = false
    
    /// A closure that is called when the button next to a row is pressed.
    var action: ((_ index: Int) -> Void)?
    /// The SF symbol on the button in each row.
    var actionSymbolName: String?
    
    // MARK: Initializers
    init(values: [String], limit: Int = 10) {
        if values.count > limit {
            self.values = values.suffix(limit - 1) + ["\(values.count - (limit - 1)) more..."]
            valuesConcatenated = true

        } else {
            self.values = values
        }
    }
    
    // MARK: Body
    var body: some View {
        VStack {
            ForEach(Array(values.enumerated()), id: \.offset) { index, value in
                HStack {
                    if !(index == values.indices.last && valuesConcatenated) {
                        Text("\(index).")
                            .foregroundColor(.secondary)
                    }

                    Text(value)
                    
                    Spacer()

                    if action != nil && !(index == values.indices.last && valuesConcatenated) {
                        Spacer()

                        Button {
                            action!(index)
                        } label: {
                            Image(systemName: actionSymbolName ?? "questionmark")
                        }
                        .frame(alignment: .trailing)
                    }
                }
                .if((values.count - index) % 2 == 0) { view in
                    view.background(
                        Color(.systemGray5)
                            .cornerRadius(5)
                    )
                }
            }
        }
    }
}

I get the error The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions on the line var body: some View {

I've also noticed that this code causes some other problems like making the Xcode autocomplete extremely slow.

Any ideas how I might be able to solve this? It seems like a pretty simple view and I think I'm doing the ForEach how I should.

Thanks!

Cameron Delong
  • 454
  • 1
  • 6
  • 12
  • Not reproducible for me on 12.5 or 13.0b4. In the past, I've noticed that Xcode sometimes has a problem with boolean evaluation with `&&` in SwiftUI, so I'd consider building helper functions for those that can be split out. – jnpdx Aug 18 '21 at 19:47
  • Do **not** use `id` as `\.offset` - use `\.element` instead. Using offset causes issues when the elements change. – George Aug 18 '21 at 21:40

1 Answers1

0

This is a very misleading error. What it really means is you screwed something up in your body, but the compiler can't figure out the error, so it throws it on the body itself. The easiest way to find it is to comment out portions of your body in matched braces until the error goes away. In your case the issue is with this:

            .if((values.count - index) % 2 == 0) { view in
                view.background(
                    Color(.systemGray5)
                        .cornerRadius(5)
                )
            }

I am not sure what you are attempting to do, but .if is not valid syntax and I am not sure what view is or where it is supposed to come from.

Yrb
  • 8,103
  • 2
  • 14
  • 44
  • I would bet that the OP is using something like this (https://stackoverflow.com/a/57685253/560942) which is a common extension in SwiftUI – jnpdx Aug 18 '21 at 19:50
  • Yeah that’s correct about `.if`, I should have mentioned in my post. I have tried commenting out different parts of it and I can get the code to compile, however even if I remove everything but the `ForEach`, Xcode is still extremely slow. – Cameron Delong Aug 18 '21 at 19:59
  • This is why you create a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). I didn't have any issue with the ForEach. Now that I added that extension, it is building for me. Therefore, I would try the standbys: Clean the Build Folder, and delete your DerivedData folder. – Yrb Aug 18 '21 at 20:05
  • 12.5.1 I think? Whatever the newest non-beta version is. – Cameron Delong Aug 18 '21 at 20:25
  • have you cleaned the build folder and deleted the DerivedData for the project? – Yrb Aug 18 '21 at 20:27
  • I just got home and was able to try that, it didn’t seem to make any difference. – Cameron Delong Aug 18 '21 at 20:45
  • I think @jnpdx was right about the && logic being the problem. I moved each row into its own view and that didn’t help, but it made me realize that removing the code `!(index == values.indices.last && valuesConcatenated)` made it work. I also noticed that I forgot to unwrap `.last`, but doing that still didn’t fix it. – Cameron Delong Aug 18 '21 at 21:05