Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
OptTrader opened this issue Oct 31, 2016 · 7 comments
Closed

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

OptTrader opened this issue Oct 31, 2016 · 7 comments

Comments

@OptTrader
Copy link

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?

@liuxuan30
Copy link
Member

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

@OptTrader
Copy link
Author

@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

@danielgindi
Copy link
Collaborator

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.

@OptTrader
Copy link
Author

OptTrader commented Nov 2, 2016

I actually follow this suggestion - #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.

@tunds
Copy link

tunds commented Jan 8, 2017

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 ""
    
    
}

}
`

@keridano
Copy link

@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

@VipulB-iProgrammer
Copy link

@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]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants