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

Cannot remove an observer for the key path "bounds" because it is not registered as an observer #3995

Closed
1 task done
nathan-fiscaletti opened this issue May 11, 2019 · 6 comments

Comments

@nathan-fiscaletti
Copy link

What did you do?

Trying to add a Chart to a UITableViewCell, and was greeted with an error.

let cell = self.tableView.dequeueReusableCell(withIdentifier: "NetworkStatsGraphCell", for: indexPath) as! ChartCell
cell.initializeChart()
return cell
import UIKit
import Charts

class ChartCell : UITableViewCell
{
    @IBOutlet weak var chart: LineChartView!
    
    func initializeChart()
    {
        chart.backgroundColor = UIColor(white: 1, alpha: 0)
        
        chart.marker = nil;
        chart.xAxis.drawAxisLineEnabled = false
        chart.xAxis.drawGridLinesEnabled = false
        chart.xAxis.drawLabelsEnabled = false
        chart.drawBordersEnabled = false;
        chart.layoutMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        
        chart.leftAxis.drawAxisLineEnabled = false
        chart.leftAxis.drawGridLinesEnabled = false
        chart.leftAxis.drawLabelsEnabled = false
        
        chart.xAxis.enabled = false
        chart.leftAxis.enabled = false
        chart.rightAxis.enabled = false
        chart.drawBordersEnabled = false
        chart.minOffset = 0
        
        chart.rightAxis.drawAxisLineEnabled = false
        chart.rightAxis.drawGridLinesEnabled = false
        chart.rightAxis.drawLabelsEnabled = false
        chart.legend.enabled = false;
        
        let dataSet1 = LineChartDataSet([
            // First four must be 0 for design.
            ChartDataEntry(x: 0, y: 0),
            ChartDataEntry(x: 1, y: 0),
            ChartDataEntry(x: 2, y: 0),
            
            ChartDataEntry(x: 3, y: 6),
            ChartDataEntry(x: 4, y: 9),
            ChartDataEntry(x: 5, y: 5),
            ChartDataEntry(x: 6, y: 8),
            ChartDataEntry(x: 7, y: 18),
            ChartDataEntry(x: 8, y: 14),
            ChartDataEntry(x: 9, y: 12),
            
            // Last three must be 0 for design
            ChartDataEntry(x: 10, y: 0),
            ChartDataEntry(x: 11, y: 0)
            ])
        
        let dataSet2 = LineChartDataSet(values: [
            // First four must be 0 for design.
            ChartDataEntry(x: 0, y: 0),
            ChartDataEntry(x: 1, y: 0),
            ChartDataEntry(x: 2, y: 0),
            
            ChartDataEntry(x: 3, y: 6),
            ChartDataEntry(x: 4, y: 9),
            ChartDataEntry(x: 5, y: 5),
            ChartDataEntry(x: 6, y: 8),
            ChartDataEntry(x: 7, y: 18),
            ChartDataEntry(x: 8, y: 14),
            ChartDataEntry(x: 9, y: 12),
            
            // Last three must be 0 for design
            ChartDataEntry(x: 10, y: 0),
            ChartDataEntry(x: 11, y: 0)
            ],
                                        label: ""
        )
        
        dataSet1.drawIconsEnabled = false
        dataSet1.drawCirclesEnabled = false
        dataSet1.drawCircleHoleEnabled = false
        dataSet1.drawValuesEnabled = false
        dataSet1.lineCapType = .round
        dataSet1.colors = [rgbToUiColor(rgb: 0xFF0000)]
        dataSet1.highlightEnabled = false
        dataSet1.lineWidth = 2;
        dataSet1.mode = .horizontalBezier
        
        
        dataSet2.drawIconsEnabled = false
        dataSet2.drawCirclesEnabled = false
        dataSet2.drawCircleHoleEnabled = false
        dataSet2.drawValuesEnabled = false
        dataSet2.lineCapType = .round
        dataSet2.highlightEnabled = false
        dataSet2.lineWidth = 2;
        dataSet2.mode = .horizontalBezier
        dataSet2.colors = [rgbToUiColor(rgb: 0x00FF00)]
        
        let data = LineChartData(dataSets: [dataSet1, dataSet2])
        chart.data = data
        //chart.animate(xAxisDuration: 1.0, yAxisDuration: 0)
    }
    
    func rgbToUiColor(rgb: Int) -> UIColor {
        return UIColor(
            red: CGFloat((rgb >> 16) & 0xFF) / 255.0,
            green: CGFloat((rgb >> 8) & 0xFF) / 255.0,
            blue: CGFloat(rgb & 0xFF) / 255.0,
            alpha: 1.0
        );
    }
}

What did you expect to happen?

The chart to display.

What happened instead?

Was greeted with this error:

2019-05-11 09:03:46.356484-0500 Prototype Settings[25568:4941238] *** Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <Charts.ChartDataSet 0x600001d20240> for the key path "bounds" from <Charts.ChartDataSet 0x600001d20240> because it is not registered as an observer.'
*** First throw call stack:
(
	0   CoreFoundation                      0x000000010f9976fb __exceptionPreprocess + 331
	1   libobjc.A.dylib                     0x000000010e484ac5 objc_exception_throw + 48
	2   CoreFoundation                      0x000000010f997555 +[NSException raise:format:] + 197
	3   Foundation                          0x000000010df0a5e1 -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] + 488
	4   Foundation                          0x000000010df0aa68 -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] + 84
	5   Charts                              0x000000010d9f8009 $s6Charts13ChartViewBaseCfD + 105
	6   Prototype Settings                  0x000000010d609adf $s18Prototype_Settings9ChartCellC010initializeC0yyF + 6543
	7   Prototype Settings                  0x000000010d60be55 $s18Prototype_Settings14SessionDetailsC9tableView_12cellForRowAtSo07UITableF4CellCSo0kF0C_10Foundation9IndexPathVtF + 1285
	8   Prototype Settings                  0x000000010d60d5eb $s18Prototype_Settings14SessionDetailsC9tableView_12cellForRowAtSo07UITableF4CellCSo0kF0C_10Foundation9IndexPathVtFTo + 155
	9   UIKitCore                           0x000000011846d62c -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 764
	10  UIKitCore                           0x000000011846db65 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 73
	11  UIKitCore                           0x0000000118435d20 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2870
	12  UIKitCore                           0x0000000118455e37 -[UITableView layoutSubviews] + 165
	13  UIKitCore                           0x00000001187029c1 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1417
	14  QuartzCore                          0x00000001106a0eae -[CALayer layoutSublayers] + 173
	15  QuartzCore                          0x00000001106a5b88 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 396
	16  QuartzCore                          0x00000001106b1ee4 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 72
	17  QuartzCore                          0x00000001106213aa _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 328
	18  QuartzCore                          0x0000000110658584 _ZN2CA11Transaction6commitEv + 608
	19  UIKitCore                           0x000000011825c3a4 _afterCACommitHandler + 245
	20  CoreFoundation                      0x000000010f8fe0f7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
	21  CoreFoundation                      0x000000010f8f85be __CFRunLoopDoObservers + 430
	22  CoreFoundation                      0x000000010f8f8c31 __CFRunLoopRun + 1505
	23  CoreFoundation                      0x000000010f8f8302 CFRunLoopRunSpecific + 626
	24  GraphicsServices                    0x000000011462e2fe GSEventRunModal + 65
	25  UIKitCore                           0x0000000118234ba2 UIApplicationMain + 140
	26  Prototype Settings                  0x000000010d60eeab main + 75
	27  libdyld.dylib                       0x0000000111d5e541 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Charts Environment

Charts version/Branch/Commit Number: 3.2.2
Xcode version: 10.2.1 (10E1001)
Swift version: Swift 5
Platform(s) running Charts: iOS
macOS version running Xcode: Mojave 10.14.3

Demo Project

I don't have the best internet for uploads right now and the project is too large.

@nathan-fiscaletti
Copy link
Author

It looks like i get the same problem even if i do not call initializeChart(), so I assume this is an issue with using it in a UITableView

@nathan-fiscaletti
Copy link
Author

I've narrowed it down to being something about the way I'm initializing my DataSet, but i'm not sure what specifically.

@nathan-fiscaletti
Copy link
Author

I've found that if i comment out .lineCapType = .round and .drawCircleHoleEnabled = false for the data sets i get rid of this error, but then i get a new error which says Fatal error: Datasets for LineChartRenderer must conform to ILineChartDataSet

@nathan-fiscaletti
Copy link
Author

Giving the data sets different labels seems to fix the last error, which wasn't very clear. However the issue still persists that if i use lineCapType or drawCircleHoleEnabled, it fails with the Observer bug.

@liuxuan30
Copy link
Member

liuxuan30 commented May 13, 2019

I think you should go to stack overflow for this issue.
I have seen people adding Chart into a cell, but never report something like this.

    deinit
    {
        self.removeObserver(self, forKeyPath: "bounds")
        self.removeObserver(self, forKeyPath: "frame")
    }

the observer is only removed in deinit(), I'm not sure if you already see it's been added. And seems not our scope to investigate.

My bet:
your cell is getting freed very soon as well as the sub views before the chart view add the observer.

@nathan-fiscaletti
Copy link
Author

@liuxuan30 I'm not sure how it wouldn't be considered a bug that this only seems to happen when I have .lineCapType = .round and .drawCircleHoleEnabled = false enabled

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

2 participants