FlowStack
FlowStack copied to clipboard
The compiler is unable to type-check this expression in reasonable time
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
same error here
I am also having this issue. Is there any work around?
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 can you show the code you ended up with please?
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) } } } }
Sorry for the Bad format
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...
Does it work with Xcode 11.2 beta? The release notes mention improvements for this kind of issue.
Issue still exists ... any work around?
My workaround was to use https://github.com/SwiftUIExtensions/Grid which doesn't have this problem.
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))
}
}
}
}
}
}
}
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))
}
}
}
}
}
}
}
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 :)
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 :)
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.