Index Out of Range

Hello
How do I solve the Index out of range at line 81
I tried many ways, but none of them worked
Code Block
//
// ContentView.swift
// Fede
//
// Created by Jad Taljabini on 14/03/21.
//
import SwiftUI
struct ContentView: View {
@State private var media: String = ""
@State private var voto: String = ""
@State private var voti: [Float] = []
@State private var nVoti: Int = 0
@State private var test: String = ""
@State private var voti2: [Float] = []
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
NavigationView {
Form {
Section{
TextField("A che media vuoi arrivare", text: $media)
}
Section{
TextField("Quanti voti prenderai", text: $test)
}
Section{
HStack {
TextField("Tuoi voti", text: $voto)
Spacer()
Button(action: {
voti.append(Float(voto) ?? 0)
voto = ""
nVoti = nVoti + 1
}, label: {
Text("Add")
})
}
}
Section{
ForEach(voti, id: \.self){ item in
Text("\(item, specifier: "%.1f")")
}.onDelete(perform: removeRows)
}
Section(header: Text("Voti che devi prendere")){
ForEach(voti2, id: \.self){ item2 in
Text("\(item2)")
}
}
}.onReceive(timer) { input in
voti2 = tutto()
}
.navigationTitle("Media")
}
}
func tutto() -> [Float] {
let testInt = Int(test) ?? 0
let mediaFloat = Float(media) ?? 0
var mediaEffettiva = mediaEffFunzione(dim: nVoti)
if mediaEffettiva < mediaFloat {
for i in 0..<testInt - 2 {
voti2[i] = Float(Int(mediaEffettiva + 1))
}
let mediaEffettivaInt = Int(mediaEffettiva)
let mediaFloatInt = Int(mediaFloat)
var con: Int = 0
while(mediaEffettivaInt < mediaFloatInt){
for j in nVoti..<nVoti + testInt - 2{
voti[j] = voti2[j - nVoti];
}
mediaEffettiva = mediaEffFunzione(dim: nVoti + testInt)
if(mediaEffettiva < mediaFloat){
voti2[con] += 0.5
}
con = con + 1
if con >= testInt {
con = 0
}
}
}
return voti2
}
func removeRows(at offsets: IndexSet) {
voti.remove(atOffsets: offsets)
}
func mediaEffFunzione(dim: Int) -> Float {
var somma: Float = 0
for i in voti{
somma = somma + i
}
return somma / Float(dim)
}
}

Thank you very much
Answered by Claude31 in 666739022
In my previous answer I told you:

But the real point is to check if voti2.count is ever more than zero.
If not, that confirms there is a design flaw. This is what must be corrected.

You did not answer to this.
Did you check how voti2 is initialised ?

I changed it to this, but when I press Add, the simulator freezes

Normal. Before the change, you crashed at first pass in the loop, before infinite loop ! You don't crash anymore, but you enter an infinite while loop.

BTW: that means that at start, mediaEffettivaInt < mediaFloatInt is true.

In addition, looks like this code is flawed:
Code Block
while(mediaEffettivaInt < mediaFloatInt){
for j in nVoti..<nVoti + testInt - 2{
voti[j] = voti2[j - nVoti];
}
mediaEffettiva = mediaEffFunzione(dim: nVoti + testInt)
if mediaEffettiva < mediaFloat && voti2.isValidIndex(con) {
voti2[con] += 0.5
}
con = con + 1
if con >= testInt {
con = 0
}
}

mediaEffettivaInt and mediaFloatInt do not change in the loop: so either you never enter the loop or you loop indefinitely.

You do need to analyse and correct your code.

Note: you should select names that are more meaningful:
  • mediaEffettivaInt and mediaEffettiva : difficult to understand at first glance what is what (both are Int)

I have tried to use your code. Could not figure out how to use ut. And could not crash it either.
Could you show the exact and complete crash log ?
I would not be surprised that index out of range is value 0 (which means voti2 is an empty array).

But your code is surprising.

I see nowhere any item appended to voti2.

For sure, voti2 set to tutto()
But
func tutto() -> [Float] {
returns voti2 without appending any element.

So, when you write voti2 = tutto(), you copy voti2 into voti2 …

maybe you could simply do this near line 81:

Code Block
if(mediaEffettiva < mediaFloat && voti2.count >= con+1) {
voti2[con] += 0.5
}

That will avoid the crash.

But the real point is to check if voti2.count is ever more than zero.
If not, that confirms there is a design flaw. This is what must be corrected.

Note: in anycase, it is a effectively good practice to check index values are within bounds.

A very simple extension may even simplify writing
Code Block
extension Array {
func isValidIndex(_ index: Int) -> Bool {
return index >= 0 && index < self.count
}
}

Then
Code Block
if(mediaEffettiva < mediaFloat && voti2.count >= con+1 && con >= 0) {
voti2[con] += 0.5
}

becomes a bit shorter
Code Block
if mediaEffettiva < mediaFloat && voti2.isValidIndex(con) {
voti2[con] += 0.5
}



I changed it to this, but when I press Add, the simulator freezes

Code Block
//
// ContentView.swift
// Fede
//
// Created by Jad Taljabini on 14/03/21.
//
import SwiftUI
struct ContentView: View {
@State private var media: String = ""
@State private var voto: String = ""
@State private var voti: [Float] = []
@State private var nVoti: Int = 0
@State private var test: String = ""
@State private var voti2: [Float] = []
var body: some View {
NavigationView {
Form {
Section{
TextField("A che media vuoi arrivare", text: $media)
}
Section{
TextField("Quanti voti prenderai", text: $test)
}
Section{
HStack {
TextField("Tuoi voti", text: $voto)
Spacer()
Button(action: {
voti.append(Float(voto) ?? 0)
voto = ""
nVoti = nVoti + 1
tutto()
}, label: {
Text("Add")
})
}
}
Section{
ForEach(voti, id: \.self){ item in
Text("\(item, specifier: "%.1f")")
}.onDelete(perform: removeRows)
}
Section(header: Text("Voti che devi prendere")){
ForEach(voti2, id: \.self){ item2 in
Text("\(item2)")
}
}
}
.navigationTitle("Media")
}
}
func tutto() {
let testInt = Int(test) ?? 0
let mediaFloat = Float(media) ?? 0
var mediaEffettiva = mediaEffFunzione(dim: nVoti)
if mediaEffettiva < mediaFloat {
for i in 0..<testInt - 2 {
voti2[i] = Float(Int(mediaEffettiva + 1))
}
let mediaEffettivaInt = Int(mediaEffettiva)
let mediaFloatInt = Int(mediaFloat)
var con: Int = 0
while(mediaEffettivaInt < mediaFloatInt){
for j in nVoti..<nVoti + testInt - 2{
voti[j] = voti2[j - nVoti];
}
mediaEffettiva = mediaEffFunzione(dim: nVoti + testInt)
if mediaEffettiva < mediaFloat && voti2.isValidIndex(con) {
voti2[con] += 0.5
}
con = con + 1
if con >= testInt {
con = 0
}
}
}
}
func removeRows(at offsets: IndexSet) {
voti.remove(atOffsets: offsets)
}
func mediaEffFunzione(dim: Int) -> Float {
var somma: Float = 0
for i in voti{
somma = somma + i
}
return somma / Float(dim)
}
}
extension Array {
func isValidIndex(_ index: Int) -> Bool {
return index >= 0 && index < self.count
}
}


I changed it to this, but when I press Add, the simulator freezes

Using isValidIndex does not solve your issue.

You declare voti2 with initializing it to an emtpy Array.
But there are no lines in your code which appends an element to voti2,
thus voti2 stays empty and any index cannot be valid.

What sort of result do you expect in voti2 after calling tutto()?
Accepted Answer
In my previous answer I told you:

But the real point is to check if voti2.count is ever more than zero.
If not, that confirms there is a design flaw. This is what must be corrected.

You did not answer to this.
Did you check how voti2 is initialised ?

I changed it to this, but when I press Add, the simulator freezes

Normal. Before the change, you crashed at first pass in the loop, before infinite loop ! You don't crash anymore, but you enter an infinite while loop.

BTW: that means that at start, mediaEffettivaInt < mediaFloatInt is true.

In addition, looks like this code is flawed:
Code Block
while(mediaEffettivaInt < mediaFloatInt){
for j in nVoti..<nVoti + testInt - 2{
voti[j] = voti2[j - nVoti];
}
mediaEffettiva = mediaEffFunzione(dim: nVoti + testInt)
if mediaEffettiva < mediaFloat && voti2.isValidIndex(con) {
voti2[con] += 0.5
}
con = con + 1
if con >= testInt {
con = 0
}
}

mediaEffettivaInt and mediaFloatInt do not change in the loop: so either you never enter the loop or you loop indefinitely.

You do need to analyse and correct your code.

Note: you should select names that are more meaningful:
  • mediaEffettivaInt and mediaEffettiva : difficult to understand at first glance what is what (both are Int)

Index Out of Range
 
 
Q