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

Crash on getMarkerPosition #1034

Closed
128keaton opened this issue May 14, 2016 · 25 comments
Closed

Crash on getMarkerPosition #1034

128keaton opened this issue May 14, 2016 · 25 comments

Comments

@128keaton
Copy link

crashes on line #536 in BarLineChartViewBase.swift
getTransformer(data.getDataSetByIndex(dataSetIndex)!.axisDependency).pointValueToPixel(&pt)

One value in the debugger looks off:
dataSetIndex= (Int) =1

My code:

 func chartValueSelected(chartView: ChartViewBase, entry: ChartDataEntry, dataSetIndex: Int, highlight: ChartHighlight) {



        let markerPoint = chartView.getMarkerPosition(entry: entry, highlight: highlight)

        let startPoint = CGPoint(x: 10, y: self.view.center.y)
        let aView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        let popover = Popover()
        popover.show(aView, point: startPoint)


    }
@aastein
Copy link

aastein commented May 15, 2016

whats the error message associated with the crash?

@128keaton
Copy link
Author

@aastein
fatal error: unexpectedly found nil while unwrapping an Optional value

EXC_BAD_INSTRUCTION

@aastein
Copy link

aastein commented May 15, 2016

what line? what value?

@128keaton
Copy link
Author

@aastein:
line #536 in BarLineChartViewBase.swift
getTransformer(data.getDataSetByIndex(dataSetIndex)!.axisDependency).pointValueToPixel(&pt)

let markerPoint = chartView.getMarkerPosition(entry: entry, highlight: highlight)

@danielgindi
Copy link
Collaborator

How many datasets are actually in there?
Can you post the code that you use to create the datasets?

@128keaton
Copy link
Author

128keaton commented May 15, 2016

@danielgindi:
Two, one line and one bar

func configureGraphs() {
        let serialQueue: dispatch_queue_t = dispatch_queue_create("com.128keaton.refreshQueue", nil)

        dispatch_sync(serialQueue, { () -> Void in

            var insulinVals: [BarChartDataEntry] = []
            var bgVals: [ChartDataEntry] = [ChartDataEntry]()

            for i in 0 ..< self.sampleInsulin.count {

                let stopIT = self.mealsArray![i];
                let now = stopIT["date"] as! NSDate

                let then = self.getThen()
                let formatter = NSNumberFormatter.init()
                formatter.numberStyle = NSNumberFormatterStyle.NoStyle



                if (now.isBetweeen(date: then, andDate: NSDate())) {

                    let entry =  BarChartDataEntry(value: self.sampleInsulin[i] + 100, xIndex: i, label: formatter.stringFromNumber(self.sampleInsulin[i])!)
                    let meal = self.mealsArray![i] as! NSMutableDictionary
                    insulinVals.append(entry)

                    bgVals.append(ChartDataEntry(value: Double(meal["bloodGlucose"] as! String)! + 60, xIndex: i))
                }

            }

            let noDataLabel = UILabel.init(frame: (self.insulinChart?.frame)!)
            noDataLabel.textAlignment = .Center
            noDataLabel.textColor = UIColor.whiteColor()
            noDataLabel.font = UIFont.systemFontOfSize(20)
            noDataLabel.text = "NO RECENT DATA"
            noDataLabel.tag = 10101




            let highlighter = ChartHighlighter(chart: self.insulinChart!)
            self.insulinChart?.highlighter = highlighter

            let timeVals = self.getYAxisCount(self.sampleInsulin.count)
            let chartDataSet = LineChartDataSet(yVals: bgVals, label: "Blood Glucose")
            chartDataSet.setColor(UIColor.whiteColor(), alpha: 1.0);

            chartDataSet.mode = LineChartDataSet.Mode.CubicBezier
            chartDataSet.drawFilledEnabled = false
            chartDataSet.circleRadius = 5
            chartDataSet.drawValuesEnabled = false






            chartDataSet.circleColors = [UIColor.whiteColor()]
            chartDataSet.circleHoleColor = UIColor(hue: 0.0528, saturation: 1, brightness: 0.97, alpha: 1.0)
            chartDataSet.fillAlpha = 1.0




            let barChartDataSet = BarChartDataSet(yVals: insulinVals, label: "Insulin Units")
            barChartDataSet.drawValuesEnabled = true

            barChartDataSet.valueTextColor = UIColor.lightGrayColor()
            barChartDataSet.setColor(UIColor.whiteColor())
            barChartDataSet.barSpace = 0.9


            let data: CombinedChartData = CombinedChartData(xVals: timeVals)

            data.lineData = LineChartData(xVals: timeVals, dataSets: [chartDataSet])
            data.barData = BarChartData(xVals: timeVals, dataSets: [barChartDataSet])



            if self.sampleInsulin.count == 0 {
                self.insulinChart!.rightAxis.labelTextColor = UIColor.clearColor()
                self.insulinChart!.leftAxis.labelTextColor = UIColor.clearColor()
            }

            self.insulinChart!.xAxis.labelPosition = .Top
            self.insulinChart!.animate(xAxisDuration: 0.5, yAxisDuration: 1.0)
            self.insulinChart?.setYAxisMaxWidth(.Left, width: 40)



            self.insulinChart?.xAxis.labelTextColor = UIColor.whiteColor()
            self.insulinChart?.notifyDataSetChanged()

            if bgVals.count != 0 {
                self.insulinChart?.setVisibleXRangeMaximum(CGFloat(bgVals.count))
                self.insulinChart?.xAxis.axisMaxValue = 400
                self.insulinChart?.leftAxis.axisMaxValue = 400

                self.insulinChart?.leftAxis.axisMinValue = 0
                self.insulinChart?.data = data
                print("BG vals: \(bgVals.count)")
                self.insulinChart?.notifyDataSetChanged()
                self.insulinChart?.setNeedsDisplay()
                self.insulinChart?.autoScaleMinMaxEnabled = true
            } else {
                self.insulinChart?.data = nil
                self.insulinChart?.xAxis.enabled = false

                self.insulinChart?.infoTextColor = UIColor.whiteColor()

                self.insulinChart?.setNeedsDisplay()
            }



            self.insulinChart?.autoScaleMinMaxEnabled = true

            self.view.reloadInputViews()
            self.insulinChart?.setNeedsDisplay()

        })
        //main thread
        MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
    }

@liuxuan30
Copy link
Member

@128keaton I think the error message is clear enough:
fatal error: unexpectedly found nil while unwrapping an Optional value
could you debug on your side to see what is nil?

@128keaton
Copy link
Author

@liuxuan30 its pretty vague to me:
screen shot 2016-05-15 at 9 19 41 pm

@liuxuan30
Copy link
Member

then can you trace down why dataSetIndex is -1?

@128keaton
Copy link
Author

128keaton commented May 16, 2016

@liuxuan30 I've tried, and the coding style is really confusing to follow, so I couldn't trace it.
But the values reported from the function in my controller are:
"dataSetIndex: -1 highlight.dataSetIndex: -1"

@liuxuan30
Copy link
Member

liuxuan30 commented May 16, 2016

It should be very easy for you:
in debug navigator on the left panel of Xcode, there is a full call stack that leads you here. All you need to do is go back one func at a time, to know why dataSetIndex is -1.
I checked the code, seems highlight.dataSetIndex is giving -1. So we can find out why highlight calculate the dataSetIndex is -1.
And there is ChartHighlighter class that handles user highlights.

@128keaton
Copy link
Author

@liuxuan30 we have BarLineChartViewBase.swift:

   @objc private func tapGestureRecognized(recognizer: NSUITapGestureRecognizer)
    {
        if _data === nil
        {
            return
        }

        if (recognizer.state == NSUIGestureRecognizerState.Ended)
        {
            if !self.isHighLightPerTapEnabled { return }

            let h = getHighlightByTouchPoint(recognizer.locationInView(self))

            if (h === nil || h!.isEqual(self.lastHighlighted))
            {
                self.highlightValue(highlight: nil, callDelegate: true)
                self.lastHighlighted = nil
            }
            else
            {
                self.lastHighlighted = h
////THIS IS THE LINE V
                self.highlightValue(highlight: h, callDelegate: true)
            }
        }
    }

and ChartViewBase.swift:

 /// Highlights the value selected by touch gesture.
    public func highlightValue(highlight highlight: ChartHighlight?, callDelegate: Bool)
    {
        var entry: ChartDataEntry?
        var h = highlight

        if (h == nil)
        {
            _indicesToHighlight.removeAll(keepCapacity: false)
        }
        else
        {
            // set the indices to highlight
            entry = _data?.getEntryForHighlight(h!)
            if (entry == nil)
            {
                h = nil
                _indicesToHighlight.removeAll(keepCapacity: false)
            }
            else
            {
                if self is BarLineChartViewBase
                    && (self as! BarLineChartViewBase).isHighlightFullBarEnabled
                {
                    h = ChartHighlight(xIndex: h!.xIndex, value: Double.NaN, dataIndex: -1, dataSetIndex: -1, stackIndex: -1)
                }

                _indicesToHighlight = [h!]
            }
        }

        if (callDelegate && delegate != nil)
        {
            if (h == nil)
            {
                delegate!.chartValueNothingSelected?(self)
            }
            else
            {
                // notify the listener
////THIS IS THE LINE V
                delegate!.chartValueSelected?(self, entry: entry!, dataSetIndex: h!.dataSetIndex, highlight: h!)
            }
        }

        // redraw the chart
        setNeedsDisplay()
    }

@liuxuan30
Copy link
Member

Yes I know the code, but we need to know why dataSetIndex is calculated as -1
you have to navigate to the func in the call stack where gives -1

@liuxuan30
Copy link
Member

liuxuan30 commented May 16, 2016

for example, in bar chart highlighter where gets the dataSetIndex:
xc
Becaues it will check negative value, we have no idea why it's -1

@128keaton
Copy link
Author

@liuxuan30 ok. Looks like for some reason this in ChartHighlighter:

 public func getHighlight(x x: CGFloat, y: CGFloat) -> ChartHighlight?
    {
        let xIndex = getXIndex(x)

        guard let
            selectionDetail = getSelectionDetail(xIndex: xIndex, y: y, dataSetIndex: nil)
            else { return nil }

        return ChartHighlight(xIndex: xIndex, value: selectionDetail.value, dataIndex: selectionDetail.dataIndex, dataSetIndex: selectionDetail.dataSetIndex, stackIndex: -1)
    }

is only returning -1 because of the math on the last line...which eventually gets this line:
_leftAxisTransformer = ChartTransformer(viewPortHandler: _viewPortHandler)

which is literally:
_viewPortHandler = viewPortHandler in ChartTransformer.swift

@liuxuan30
Copy link
Member

liuxuan30 commented May 16, 2016

You mean stackIndex: -1? It is not dataSetIndex.
you have to check BarChartHighlighter ( I think you are using bar chart, right?) getHighlight and getSelectionDetail. Check my screenshot above

@128keaton
Copy link
Author

128keaton commented May 16, 2016

@liuxuan30 no, CombinedChart,
In the CombinedChartData:

if highlight.dataSetIndex >= data.dataSetCount
        {
            return nil
        }

@liuxuan30
Copy link
Member

liuxuan30 commented May 16, 2016

oh man, you have to say it's a combined chart first. My bad
Could you please debug on your side? I guess you know how? I think we are close to the answer, but I don't have your laptop

@128keaton
Copy link
Author

128keaton commented May 16, 2016

@liuxuan30 what do you want me to debug? I'm really confused...

I appreciate the help, but I feel like this is an issue with the library, and since I didn't write the library, and the coding styles are so different, its very confusing to peel through, when for the past three months, I've been looking at my code and my head is filled with my style, functions, etc...

Just really maddening when this is the last issue I have before I can submit this application on ITC

@liuxuan30
Copy link
Member

liuxuan30 commented May 16, 2016

follow the call stack to figure out why it returns -1.
in getSelectionDetailsAtIndex which is in getSelectionDetail

@liuxuan30
Copy link
Member

@128keaton
Copy link
Author

@liuxuan30 ok

@128keaton
Copy link
Author

it looks like its something with highlightFullBar

@liuxuan30
Copy link
Member

@danielgindi I had a chat with @128keaton , now he can't reproduce any more, but we were able to several times.

Some context: @128keaton calls getMarkerPosition() in custom chartValueSelected delegate. Then,
During the crash, I see some things:
in public func highlightValue(highlight highlight: ChartHighlight?, callDelegate: Bool)
ycb3s
ztbdi

In the picture, highlight object gives a reasonable value, while h is not.

I walk through the code, and find that

                if self is BarLineChartViewBase
                    && (self as! BarLineChartViewBase).isHighlightFullBarEnabled
                {
                    h = ChartHighlight(xIndex: h!.xIndex, value: Double.NaN, dataIndex: -1, dataSetIndex: -1, stackIndex: -1)
                }

                _indicesToHighlight = [h!]

However, @128keaton said he never touches highlightFullBarEnabled, so it is false all the time. Anyway, @128keaton can't reproduce anymore, so we keep an eye on for this.

@danielgindi
Copy link
Collaborator

danielgindi commented May 16, 2016

It might be a Clean->Build issue. If the code shows a clear check for -1 but in runtime it's faulty, then the code was just not recompiled after a pull from the repo. Xcode bug...

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

4 participants