Xcode报错:Non-constant range: argument must be an integer literal
Xcode报错:Non-constant range: argument must be an integer literal

Xcode报错:Non-constant range: argument must be an integer literal

问题描述

在练习一个小游戏时,发现ForEach报如下错误:

Non-constant range: argument must be an integer literal

报错代码为:

ForEach(0..<QNum3Count) { num in

经排查发现报错的原因为ForEach的范围参数必须是常量和确定的值,我的ForEach中QNum3Count是一个计算属性,只有在运算时才能确定,因此编译器无法在编译时推断这个范围,因此产生该报错并造成游戏崩溃。

var QNum3Count: Int {
      return Int(String(QNum3).count)
}

因此,我应该将QNum3Count变量由计算属性改为具体的值。

@State private var QNum3Count: Int = 1   // 乘法1h和乘法2的个数

并将QNum3Count的计算放到onAppear的函数中。

func RandomQue() {
    QNum1 = Int.random(in: 1..<MulRange+1)
    QNum2 = Int.random(in: 1..<MulRange+1)
    QNum3Count = Int(String(QNum3).count)
    userAnswer = Array(repeating: "", count: QNum3Count)
}

.onAppear {
    RandomQue()
}

问题延续

修改代码后,发现崩溃并没有解决。即使我运行“Clean Build Folder..”或强退Xcode。

经排查发现,这里崩溃的原因是另一个ForEach存在报错,报错代码如下:

ForEach(0..<QNum3Count,id: \.self) { index in
    TextField("", text: Binding(
        get: {
            userAnswer[index]
        }, set: { newValue in
            if newValue.count <= 1 && newValue.allSatisfy({$0.isNumber})  {
                userAnswer[index] = newValue
            }
        }
    ))
    .keyboardType(.decimalPad)
    .frame(width: 60, height: 80)
    .multilineTextAlignment(.center)  // 多行文本对齐
    .font(.system(size: 50))
    .foregroundColor(Color.white)
}

在这里报错的原因为index超出userAnswer数组的范围,导致数组访问越界。因此,需要给上面的TextField加一个判断,当index大于或等于userAnswer[index]时,返回””空。

TextField("", text: Binding(
        get: {
            if index < userAnswer.count {
                return userAnswer[index]
            } else {
                return ""
            }
        }, set: { newValue in
            if newValue.count <= 1 && newValue.allSatisfy({$0.isNumber}) && index < userAnswer.count {
                userAnswer[index] = newValue
            }
        }
    ))

问题总结,本次实际上是两个问题,特别注意的是,当数组存在访问越界的情况,Xcode的预览效果都会存在报错或模拟器闪退的情况。

完整代码

struct Game: View {
    @Binding var mulTableNum: Int   // 跳转视图
    @Binding var MulRange: Int  // 乘法表范围
    @Binding var MulNum: Int    // 题目数量
    @Binding var QNum: Int    // 当前题目数
    @State private var QNum1: Int = 1   // 乘法1变量
    @State private var QNum2: Int = 1   // 乘法2变量
    @State private var QNum3Count: Int = 1   // 乘法1h和乘法2的个数
    var QNum3: Int {
        return QNum1 * QNum2
    }
    
    @State private var userAnswer = [String]()
    
    var title: String = "乘法测试"
    
    func RandomQue() {
        QNum1 = Int.random(in: 1..<MulRange+1)
        QNum2 = Int.random(in: 1..<MulRange+1)
        QNum3Count = Int(String(QNum3).count)
        userAnswer = Array(repeating: "", count: QNum3Count)
    }
    
    func getFullAnswer() -> String {
        return userAnswer.joined()
    }
    
    var body: some View {
        NavigationStack {
            VStack {
                Spacer()
                    .frame(height: 50)
                Text("共有 \(MulNum) 道题,当前为第 \(QNum) 道题")
                    .font(.title2)
                Spacer()
                    .frame(height: 50)
                HStack {
                    Text("\(QNum1)")
                        .font(.largeTitle)
                        .frame(width: 60, height: 80)
                        .foregroundColor(Color.white)
                        .background(Color.blue)
                    Text("*")
                        .font(.system(size: 60))
                    Text("\(QNum2)")
                        .font(.largeTitle)
                        .frame(width: 60, height: 80)
                        .foregroundColor(Color.white)
                        .background(Color.blue)
                    Text("=")
                        .font(.system(size: 60))
                    Text("?")
                        .font(.largeTitle)
                        .frame(width: 60, height: 80)
                        .foregroundColor(Color.white)
                        .background(Color.blue)
                }
                Spacer()
                    .frame(height: 60)
                Text("请输入你的答案")
                    .font(.system(size: 30))
                ZStack {
                    HStack {
                        ForEach(0..<QNum3Count,id: \.self) { num in
                            Text("")
                                .font(.largeTitle)
                                .frame(width: 60,height: 80)
                                .foregroundColor(Color.white)
                                .background(Color.blue)
                            if num != QNum3Count {
                                Spacer()
                                    .frame(width: 20)
                            }
                        }
                    }
                    HStack {
                        ForEach(0..<QNum3Count,id: \.self) { index in
                            TextField("", text: Binding(
                                get: {
                                    if index < userAnswer.count {
                                        return userAnswer[index]
                                    } else {
                                        return ""
                                    }
                                }, set: { newValue in
                                    if newValue.count <= 1 && newValue.allSatisfy({$0.isNumber}) && index < userAnswer.count {
                                        userAnswer[index] = newValue
                                    }
                                }
                            ))
                            .keyboardType(.decimalPad)
                            .frame(width: 60, height: 80)
                            .multilineTextAlignment(.center)  // 多行文本对齐
                            .font(.system(size: 50))
                            .foregroundColor(Color.white)
                        }

                    }
                }
                Button("提交答案") {
                    let answer = getFullAnswer()
                    if Int(answer) == QNum3 {
                        print("恭喜你答对了")
                    } else {
                        print("很抱歉,答错了")
                    }
                    RandomQue()
                }
                Spacer()
            }
            .navigationTitle(title)
            .navigationBarItems(
                leading: Button(action: {
                    mulTableNum = 1
                }, label: {
                    Image(systemName: "arrow.backward")
                        .font(.title)
                        .foregroundColor(Color.black)
                })
            )
            .onAppear {
                RandomQue()
            }
        }
    }
}

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注