Search code examples
iosswift3shinobi

Custom data source object not creating correctly


I'm currently experimenting with ShinobiCharts, and have created a new project in which to do this.

I have an object with a custom initialiser that conforms to a data source protocol:

import ShinobiCharts
import UIKit

class GraphDataSource: NSObject, SChartDatasource {

    let data: [Double]

    /* Initialisation Methods */
    init(data: [Double]) {
        self.data = data
    }

    /* SChartDatasource Methods */
    func numberOfSeries(in chart: ShinobiChart) -> Int {
        return 1
    }

    func sChart(_ chart: ShinobiChart, seriesAt index: Int) -> SChartSeries {
        return SChartColumnSeries()
    }

    func sChart(_ chart: ShinobiChart, numberOfDataPointsForSeriesAt seriesIndex: Int) -> Int {
        return data.count
    }

    func sChart(_ chart: ShinobiChart, dataPointAt dataIndex: Int, forSeriesAt seriesIndex: Int) -> SChartData {
        return dataPoint(forDataIndex: dataIndex)
    }

    func dataPoint(forDataIndex dataIndex: Int) -> SChartData {
        return SChartDataPoint(xValue: dataIndex, yValue: data[dataIndex])
    }

}

I then assign an instance of this object as the data source of a chart:

let data: [Double] = [0, 0, 0, 0, 0, 0, 10, 10, 30, 50, 100, 100, 80, 40, 30, 50, 40, 70, 20, 10, 10, 10, 0, 0]

...

let dataSource = DayGraphDataSource(data: data)

chart.datasource = dataSource

This however causes the app to crash, complaining that -[<classname> numberOfSeriesInSChart:]: unrecognized selector sent to instance, where <classname> could be seemingly any class name. I've seen it as __NSCFNumber and NSISRestrictedToZeroMarkerVariable among others - it seems to change on fresh installs of the app.

However, if I put a breakpoint on the line that actually sets the datasource on the chart to be this custom object and print out the instance I've created, then continue execution, the app runs absolutely fine.

When I had the view controller itself as the data source, with the exact same datasource implementation, everything worked as expected.


Solution

  • When I had the view controller itself as the data source, with the exact same datasource implementation, everything worked as expected.

    This seems to suggest that the data source instance is being deallocated early.

    The chart only holds a weak reference to its data source so something needs to ensure it hangs around. Could you check the datasource is kept alive for the entire lifecycle of the chart by assigning it to a property e.g.

    class ViewController: UIViewController {
        var dataSource: DayGraphDataSource?
    
        override func viewDidLoad() {
              // chart setup code
              dataSource = DayGraphDataSource(data: data)
              chart.datasource = dataSource
        } 
    }