0

I want to use ANDLineChartView, an API written in Objective C to create charts as views in ios, in my Swift app. What I have tried so far is simply adding the Objective-C source code to my swift project and adding a bridging header with one line of code in it (obj-c):

#import "AndLineChartView.h"

This allows me to make objects of type ANDLineChartView in my swift code. The problem is that ANDLineChartView needs a dataSource that conforms to a protocol called ANDLineChartViewDataSource, so I programmed (in Swift) an @objc class that conforms to this protocol (and I extended NSObject, so it also conforms to NSObjectProtocol which is necessary as well). I implemented, in Swift, all the necessary methods needed by ANDLineChartViewDataSource, and finally added:

#import "MyProjectName-Swift.h"

Where MyProjectName is of course my project name to ANDLineChartView.m. From what I have learned across the internet, this is the standard way to use Objective C code in Swift projects and vice versa. I therefore went on to create an instance of ANDLineChartView and set its dataSource property to an instance of my class that implements ANDLineChartViewDataSource.

*** Assertion failure in -[ANDLineChartView numberOfElements], /path/ANDLineChartView.m:158 Data source is not set.

Generated by these lines of code in ANDLineChartView.m:

- (NSUInteger)numberOfElements{
  if(_dataSource && [_dataSource respondsToSelector:@selector(numberOfElementsInChartView:)]){
    return [_dataSource numberOfElementsInChartView:self];
  }else{
    NSAssert(_dataSource, @"Data source is not set.");
    NSAssert([_dataSource respondsToSelector:@selector(numberOfElementsInChartView:)], @"numberOfElementsInChartView: not implemented.");
    return 0;
  }
}

My first thought was that my functions were not visible as Objective C selectors, so I changed NSObjects responds(to aSelector : Selector!) -> Bool method:

  public override func responds(to aSelector: Selector!) -> Bool {
    if aSelector == #selector(numberOfElements(in:)) ||
       aSelector == #selector(numberOfGridIntervals(in:)) ||
       aSelector == #selector(chartView(_:valueForElementAtRow:)) ||
       aSelector == #selector(chartView(_:descriptionForGridIntervalValue:)) ||
       aSelector == #selector(maxValueForGridInterval(in:)) ||
       aSelector == #selector(minValueForGridInterval(in:)) {
         return true
     } else {
         return super.responds(to: aSelector)
    }
  }

And here is my declaration of the chart and the dataSource:

third = ANDLineChartView(frame : CGRect(x : 0,
                                        y : 0,
                                        width : UIScreen.main.bounds.width,
                                        height : Main.screenSegment * 9.5))

third.dataSource = GoalData(data: UserData.past)

Where GoalData is my ANDChartViewDataSource class, which is initialized with an array, UserData.past.

I continued to get the same error message though, and at this point, especially because I haven't even used bridging headers etc. in my projects before, I have come here for help. I also don't know Objective C, so a solution that does not have to do with rewriting my dataSource class in Objective C would be awesome. Alternatively, if you have any suggestions for chart APIs written in Swift, that would be helpful too, because then I wouldn't have to worry about this. But I am also genuinely curious, so...

Thanks lots for any help.

Similar Question

NSObjectProtocol Documentation

Liam Keeley
  • 187
  • 1
  • 10
  • 1
    The error message shows **_Data source is not set._**. Which means `dataSource` property of `ANDLineChartView` is not yet set when needed. Please show your Swift code where `ANDLineChartView` is set up. One more, you have no need to add `#import "MyProjectName-Swift.h"` into the .m files of a Library, unless you have modified other parts of the Library. – OOPer Sep 15 '18 at 04:02
  • Ok I added the declaration of the instance and the dataSource. – Liam Keeley Sep 15 '18 at 04:19
  • 1
    `dataSource` is a weak property. You need to keep strong reference to the dataSource instance somewhere else. – OOPer Sep 15 '18 at 04:38
  • Please post an Answer by yourself. – OOPer Sep 15 '18 at 04:59

1 Answers1

1

The issue was that I just assigned dataSource to GoalData, but dataSource is a weak property, so unless something else kept my instance of GoalData alive, it would become nil and caused the app to fail because dataSource had no value.

I added this to my class that implemented my instance of ANDLineChartView:

var dataSource : GoalData?

Then I added in my initializer:

self.dataSource = GoalData(data : UserData.past)
third = ANDLineChartView(frame : CGRect(x : 0,
                                    y : 0,
                                    width : UIScreen.main.bounds.width,
                                    height : Main.screenSegment * 9.5))

third.dataSource = self.dataSource
Liam Keeley
  • 187
  • 1
  • 10