Charts / Swift 3.0 - Fatal error: Index out of range

Created on 31 Oct 2016  路  7Comments  路  Source: danielgindi/Charts

I have a segmentControl with time range (1D, 3M, 1Y, 5Y) to perform network call and fetch data from Yahoo. First, I had to add a method for my String values for x-axis with the following:

class XAxisStringValueFormatter: NSObject, IAxisValueFormatter {
    private var sValues: [String] = []
    init(values: [String]) {
        sValues = values
    }
    func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        return sValues[Int(value)]
    }
}

In my LineChartViewController, I have a delegate for the timeRange change to perform my networkCall:

 func networkCall(range: ChartRange) {
        let symbol = self.symbol
        YahooFinanceApiClient.requestEquityChartpoints(symbol: symbol, range: range, onSuccess: { chartpts in
            self.createLineChart(range: range, chartpoints: chartpts)
            }, onError: { error in
                print("Error: \(error.localizedDescription)")
        })
    }

Here is my create Line ChartView:

func createLineChart(range: ChartRange, chartpoints: [EquityChartpoint]) {
        // set data
        var xValues: [String] = []
        var yValues: [Double] = []
        for object in chartpoints {
            switch range {
            case .OneDay:
                let x = Formatters.sharedInstance.stringFromHours(date: object.date)
                xValues.append(x!)
            case .ThreeMonth, .OneYear, .FiveYear:
                let x = Formatters.sharedInstance.stringFromDate(date: object.date)
                xValues.append(x!)
            }
            let y = object.close
            yValues.append(y!)
        }
        // charting
        let formatter: XAxisStringValueFormatter = XAxisStringValueFormatter(values: xValues)
        let xaxis: XAxis = XAxis()
        var dataEntries: [ChartDataEntry] = []
        for i in 0..<xValues.count {
            let dataEntry = ChartDataEntry(x: Double(i), y: yValues[i], data: xValues as AnyObject)
            dataEntries.append(dataEntry)
        }
        xaxis.valueFormatter = formatter

        let lineChartDataSet = LineChartDataSet(values: dataEntries, label: "Price")

        let data: LineChartData = LineChartData(dataSets: [lineChartDataSet])
        self.lineChartView.data = data
        self.lineChartView.xAxis.valueFormatter = xaxis.valueFormatter  
    }

I have a Fatal Error - Index out of range when I moved from "3M" to "1Y". I checked the xValues count to match yValues for each time range. It appears the error arrived at that xAxisStringValueFormatter where yValues count does not match the xValues. Seems strange to me. Any idea what I did wrong?

Most helpful comment

@tunds I think there is a little error in your workaround. It should be
if val >= 0 && val < myArr.count { return myArr[Int(val)] }
otherwise the app would throw an Index out of range error when val = myArr.count

All 7 comments

where the error happens? for a wild guess, return sValues[Int(value)] ?

@liuxuan30 That's correct. You can see the attached screenshot where the values don't match up to sValues. I already checked to make sure each xValues count matches yValues count for each segment.
screen shot 2016-10-31 at 10 41 36 am

value is not an index, it's a value. It could be _any_ value. It may not be your only crash - you may encounter values that Swift will refuse to cast to Int just like that, because they are in the 64bit dimension. You may encounter decimal values or values our of your expected range.

If you insist on using value as an index, you should put that in a variable first, and check for being "in range", obviously, to avoid the "Index out of range" exception.

I actually follow this suggestion - https://github.com/danielgindi/Charts/issues/1340

To follow up your comment, I searched around to figure out a solution to this issue. Still, I'm not sure what I need to do to fix this. Can you offer some suggestion? Apologize for any inconvenience.

A fix i did was the following code hopefully it helps.

`
@objc(ChartFormatter)
class ChartFormatter: NSObject, IAxisValueFormatter {

// The array of values to show on x axis
private var myArr: [String]!

init(myArr: [String]) {


    self.myArr = myArr
}

func stringForValue(_ value: Double, axis: AxisBase?) -> String {

    let val = Int(value)

    if val >= 0 && val <= myArr.count {

        return myArr[Int(val)]

    }

    return ""


}

}
`

@tunds I think there is a little error in your workaround. It should be
if val >= 0 && val < myArr.count { return myArr[Int(val)] }
otherwise the app would throw an Index out of range error when val = myArr.count

@tunds Plz do the following changes your code will work..Crash occurs when there is only one reading ....
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
return myArr[Int(value) % myArr.count]
}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Shunshine07 picture Shunshine07  路  3Comments

coop44483 picture coop44483  路  3Comments

BrandonShega picture BrandonShega  路  4Comments

kwstasna picture kwstasna  路  3Comments

deepumukundan picture deepumukundan  路  3Comments