FlowStack icon indicating copy to clipboard operation
FlowStack copied to clipboard

The compiler is unable to type-check this expression in reasonable time

Open farcaller opened this issue 6 years ago • 15 comments

It seems that beta5 broke the code: .../SourcePackages/checkouts/FlowStack/Sources/FlowStack/FlowStack.swift:35:5: The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

farcaller avatar Jul 30 '19 10:07 farcaller

same error here

Tobias-Bauer avatar Jul 31 '19 19:07 Tobias-Bauer

I am also having this issue. Is there any work around?

rossbigelow avatar Aug 10 '19 01:08 rossbigelow

I did it on my own without flow stack with two ForEach loops I can send you the file if you want it

Tobias-Bauer avatar Aug 10 '19 06:08 Tobias-Bauer

@Tobias-Bauer can you show the code you ended up with please?

farcaller avatar Sep 18 '19 21:09 farcaller

I did it like This I don‘t know if it will work for you because i passed the rows down to this View Good luck 👍 struct List : View { var rows: Array(0..<data.count).map { $0 }.chunked(into: 3) var spacing: CGFloat = (screen.width-330)/4 var list: [ReminderModel] var number: Int var body: some View { return VStack { ForEach(rows, id: \.self) { row in HStack(spacing: self.spacing) { ForEach(row, id: \.self) { item in Group { //Put your content here } } Spacer() }.padding(.top, self.spacing).padding(.leading, self.spacing) } } } }

Tobias-Bauer avatar Sep 20 '19 14:09 Tobias-Bauer

Sorry for the Bad format

Tobias-Bauer avatar Sep 20 '19 14:09 Tobias-Bauer

I did something similar, it seems that in the end getting rid of generics helps.

tfw you need to change your code to make the compiler happy...

farcaller avatar Sep 20 '19 16:09 farcaller

Does it work with Xcode 11.2 beta? The release notes mention improvements for this kind of issue.

funkenstrahlen avatar Oct 08 '19 13:10 funkenstrahlen

Issue still exists ... any work around?

ShaharHD avatar Oct 17 '19 05:10 ShaharHD

My workaround was to use https://github.com/SwiftUIExtensions/Grid which doesn't have this problem.

farcaller avatar Oct 17 '19 09:10 farcaller

The author has to find out a proper way... For now check this out

import SwiftUI

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public struct FlowStack<Content>: View where Content: View {
  // The number of columns we want to display
  var columns: Int
  // The total number of items in the stack
  var numItems: Int
  // The alignment of our columns in the last row
  // when they don't fill all the column slots
  var alignment: HorizontalAlignment

    var count : Int
    var count1 : Int
    var innerCount : Int
    var contentIndex : Int
    var vSpacing : CGFloat = 0.0
    var hSpacing : CGFloat = 0.0
    var sizeOfItem : Int
    
  public let content: (Int, CGFloat) -> Content

  public init(
    columns: Int,
    numItems: Int,
    alignment: HorizontalAlignment?,
    @ViewBuilder content: @escaping (Int, CGFloat) -> Content) {
    self.content = content
    self.columns = columns
    self.numItems = numItems
    self.alignment = alignment ?? HorizontalAlignment.leading
    sizeOfItem = self.numItems / self.columns
    contentIndex   =  sizeOfItem * self.columns
    innerCount = self.columns - 1
    count1 = self.numItems % self.columns
    count = self.numItems / self.columns
  }

  public var body : some View {
    // A GeometryReader is required to size items in the scroll view
    GeometryReader { geometry in
      // Assume a vertical scrolling orientation for the grid
      ScrollView(Axis.Set.vertical) {
        // VStacks are our rows
        VStack(alignment: self.alignment) {
            ForEach(0 ..< self.count) { row in
            // HStacks are our columns
            HStack() {
                ForEach(0 ... self.innerCount,id: \.self) { column in
                self.content(
                  row * self.columns + column,
                  geometry.size.width/CGFloat(self.columns)
                ).frame(width: geometry.size.width/CGFloat(self.columns))
                // Size the content to frame to fill the column
              }
            }
          }
          // Last row
          // HStacks are our columns
          HStack() {
            ForEach(0 ..< self.count1) { column in
              self.content(
                // Pass the index to the content
                self.contentIndex + column,
                // Pass the column width to the content
                geometry.size.width/CGFloat(self.columns)
              )
              // Size the content to frame to fill the column
              .frame(width: geometry.size.width/CGFloat(self.columns))
            }
          }
        }
      }
    }
  }
}

karthisiva-ios avatar Oct 18 '19 09:10 karthisiva-ios

First of: nice simple solution, I like it! And... I ran into the same issue: so I did a little digging and trial and error.

I tried to work around the issue, as well, building my own foreach loops, but that resulted in really cluttered code, also repetitive as I needed this solutions in several places. So I did a little refactoring on the original code and ended up with the following. And it performs really nice.

//
//  FlowStack.swift
//
//  Created by John Susek on 6/25/19.
//  Copyright © 2019 John Susek. All rights reserved.
//
import SwiftUI

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public struct FlowStack<Content>: View where Content: View {
	// The number of columns we want to display
	var columns: Int
	// The total number of items in the stack
	var numItems: Int
	// The alignment of our columns in the last row
	// when they don't fill all the column slots
	var alignment: HorizontalAlignment
	
	public let content: (Int, CGFloat) -> Content
	
// <--- refactoring start

	private func width(for size: CGSize)-> CGFloat {
		return size.width/CGFloat(self.columns)
	}
	
	private func index(forRow row: Int, column: Int) -> Int {
		return (row * self.columns) + column
	}
	
	private var lastRowColumns : Int { get { return numItems % columns }	}
	
	private var rows : Int { get { return numItems / columns } }

// <--- refactoring end
	
	public init(
		columns: Int,
		numItems: Int,
		alignment: HorizontalAlignment?,
		@ViewBuilder content: @escaping (Int, CGFloat) -> Content) {
		self.content = content
		self.columns = columns
		self.numItems = numItems
		self.alignment = alignment ?? HorizontalAlignment.leading
	}

	public var body : some View {
		// A GeometryReader is required to size items in the scroll view
		GeometryReader { geometry in
			
			// Assume a vertical scrolling orientation for the grid
			ScrollView(Axis.Set.vertical) {
				
				// VStacks are our rows
				VStack(alignment: self.alignment, spacing: 0) {
					ForEach(0 ..< self.rows ) { row in
						
						// HStacks are our columns
						HStack(spacing: 0) {
							ForEach(0 ..< self.columns) { column in
								self.content(
									// Pass the index to the content
									self.index(forRow: row, column: column),
									// Pass the column width to the content
									self.width(for: geometry.size)
								)
									// Size the content to frame to fill the column
									.frame(width: self.width(for: geometry.size))
							}
						}
					}
					
					// Last row
					// HStacks are our columns
					HStack(spacing: 0) {
						ForEach(0 ..< self.lastRowColumns) { column in
							self.content(
								// Pass the index to the content
								self.index(forRow: self.rows, column: column),
								// Pass the column width to the content
								self.width(for: geometry.size)
							)
								// Size the content to frame to fill the column
								.frame(width: self.width(for: geometry.size))
						}
					}
				}
			}
		}
	}
}

GoldenStat avatar Oct 23 '19 11:10 GoldenStat

First of: nice simple solution, I like it! And... I ran into the same issue: so I did a little digging and trial and error.

I tried to work around the issue, as well, building my own foreach loops, but that resulted in really cluttered code, also repetitive as I needed this solutions in several places. So I did a little refactoring on the original code and ended up with the following. And it performs really nice.

...

Create a PR then, get recognized :)

ShaharHD avatar Oct 27 '19 10:10 ShaharHD

First of: nice simple solution, I like it! And... I ran into the same issue: so I did a little digging and trial and error.

I tried to work around the issue, as well, building my own foreach loops, but that resulted in really cluttered code, also repetitive as I needed this solutions in several places. So I did a little refactoring on the original code and ended up with the following. And it performs really nice.

···

Great solution :)

shevakuilin avatar Oct 30 '19 06:10 shevakuilin

Nice solution - thank you - but i am having a problem using this when i dynamically change the size of the grid. In my scenario i am using the grid to display a set of wheels - when i add a new wheel via a modal i get complaints for not using constant values in the ForEach loop when i try and refresh the view .

My call to Flowstack is:

FlowStack(columns: 2, numItems: wheelsCount, alignment: .center) { index, colWidth in NavigationLink(destination: ModWheelView(wheel: self.$bleConnection.wheelListVM.wheels[(index)], index: (index), inDetail: self.$inDetail), isActive: self.$model.pushed[(index)]) { return DialRepresentation(wheel: self.$bleConnection.wheelListVM.wheels[(index)], dialMask: 0) }.frame(width: colWidth) }

the error i get is: ForEach<Range<Int>, Int, HStack<ForEach<Range<Int>, Int, ModifiedContent<ModifiedContent<NavigationLink<DialRepresentation, ModWheelView>, _FrameLayout>, _FrameLayout>>>> count (2) != its initial count (1). ForEach(_:content:) should only be used for constant data. Instead conform data to Identifiable or use ForEach(_:id:content:) and provide an explicit id! ForEach<Range<Int>, Int, ModifiedContent<ModifiedContent<NavigationLink<DialRepresentation, ModWheelView>, _FrameLayout>, _FrameLayout>> count (0) != its initial count (1). ForEach(_:content:) should only be used for constant data. Instead conform data to Identifiable or use ForEach(_:id:content:) and provide an explicit id!

I am a novice i confess but if there is an easy solution any help greatly appreciated.

Chiefcodemonkey avatar Nov 22 '19 17:11 Chiefcodemonkey