如何使用 SwiftUI 在 Xcode 中消除 foreach 循环的歧义

Posted

技术标签:

【中文标题】如何使用 SwiftUI 在 Xcode 中消除 foreach 循环的歧义【英文标题】:How to disambiguate a foreach loop in Xcode with SwiftUI 【发布时间】:2020-02-14 16:48:17 【问题描述】:

我正在尝试在 Xcode 上使用 swiftUI 创建一个六边形网格。为了循环创建单个六边形,我使用了 foreach 循环。但是我在创建一个创建一列六边形的函数时遇到了一个错误:

private func makeCol(C: Int, Bump:Int) -> some View 
        return ZStack 
            ForEach(-5...5, id: \.self) Ynumber in                
                self.hexagon(
                    x: (ThreeRooted * self.L * Double(C)) + self.centerWidth,
                    y: (ThreeRooted * self.L * Double(Ynumber)) + self.centerHeight + (ThreeRootedOverTwo * self.L * Bump))
                    .stroke(Color.red, lineWidth: CGFloat(self.L/4.0))
            
        
    

错误: 编译器无法在合理的时间内对该表达式进行类型检查;尝试将表达式分解为不同的子表达式。

为了解决这个问题,我在单独的变量中提取了我的位置字段。但是,这又产生了另一个错误:

private func makeCol(C: Int, Bump:Int) -> some View 
        return ZStack 
            ForEach(-5...5, id: \.self) Ynumber in
                let xPlot = (ThreeRooted * self.L * Double(C)) + self.centerWidth
                let yPlot = (ThreeRooted * self.L * Double(Ynumber)) + self.centerHeight + (ThreeRootedOverTwo * self.L * Bump)

                self.hexagon(
                    x: xPlot,
                    y: yPlot)
                    .stroke(Color.red, lineWidth: CGFloat(self.L/4.0))
            
        
     

错误:无法推断复杂的闭包返回类型;添加显式类型以消除歧义。

如何给这个循环一个显式类型

【问题讨论】:

您通常不能在ForEach 中声明变量/让常量。 @RobNapier “通常最好假设您在 SwiftUI 中获得的诊断消息毫无意义”但我不建议将其作为经验法则发布; Swift 5.2 承诺了巨大的改进,让我们看看它是否能实现。 hexagon(..)函数的返回类型是什么? @Sweeper,试试这个(在需要的地方有休息,因为评论格式不允许他们):ForEach(0 ..< 100) (i) -> Text in let a = 1 return Text("Item \(i + a)") @Asperi 我说的是“一般”... 【参考方案1】:

ForEach 是一个结构,它根据已识别数据的基础集合计算按需视图,不是循环

如何创建六边形网格?下面是一种可能的方法,我试图向您展示如何使用 ForEach 和 SwiftUI 声明性语法。

import SwiftUI

struct Hexagon: Shape 
    func path(in rect: CGRect) -> Path 
        Path  (path) in
            path.move(to: .init(x: rect.midX, y: rect.minY))
            path.addLine(to: .init(x: rect.maxX, y: (rect.minY + rect.midY) / 2 ))
            path.addLine(to: .init(x: rect.maxX, y: (rect.maxY + rect.midY) / 2 ))
            path.addLine(to: .init(x: rect.midX, y: rect.maxY))
            path.addLine(to: .init(x: rect.minX, y: (rect.maxY + rect.midY) / 2 ))
            path.addLine(to: .init(x: rect.minX, y: (rect.minY + rect.midY) / 2 ))
            path.closeSubpath()
        
    


struct ContentView: View 
    var body: some View 
        VStack(spacing: -10) 
            ForEach(0 ..< 3)  j in
                HStack(spacing: 5) 
                    ForEach(0 ..< 4)  i in
                        Hexagon()
                            .fill(Color.yellow)
                            .overlay(
                                Hexagon()
                                .stroke(Color.red, lineWidth: 5)
                            )
                            .frame(width: 50, height: 60)
                    
                
                HStack(spacing: 5) 
                    ForEach(0 ..< 3)  i in
                        Hexagon()
                            .stroke(Color.blue, lineWidth: 5)
                            .frame(width: 50, height: 60)
                    
                
            
        
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    

这是结果

为简单起见,此处固定间距和帧参数,您最好计算适当的数字。

init(Range<Int>, content: (Int) -> Content)

Data 为 Range,ID 为 Int,Content 符合时可用 查看。

你尝试使用

init(Data, id: KeyPath<Data.Element, ID>, content: (Data.Element) -> Content)

Content 符合 View 时可用。

最后我们不知道返回六边形函数的类型是什么,它可能是 Shape,但 Shape 是协议,这可能会给你带来麻烦。如果是 Shape,请尝试将返回类型定义为某个 Shape。

是的,编译器错误报告在 SwiftUI 中仍然不是很实用

【讨论】:

【参考方案2】:

如何给这个循环一个明确的类型?

ForEach(-5...5, id: \.self)  (Ynumber) -> _ExplicitType_ in
  ...
  return self.hexagon(
            ...
         )

【讨论】:

您最好向他解释一下,ForEach 是一种根据已识别数据的基础集合按需计算视图的结构,而不是循环。

以上是关于如何使用 SwiftUI 在 Xcode 中消除 foreach 循环的歧义的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Xcode Playground 中使用 SwiftUI?

不知道如何在 SwiftUI (Xcode 12.4) 中打开地图

Xcode SwiftUI 如何滚动预览画布?

在 Xcode 11 游乐场中使用 SwiftUI

SwiftUI项目如何在Xcode预览(Preview)中开启调试支持

SwiftUI项目如何在Xcode预览(Preview)中开启调试支持