I'm writing a ChartView using NSView with data obtained from a rest api using Combine. The struct PlotView is the SwiftUI View that displays the chart, ChartViewRepresentable is the bridge between the NSView with the chart and the SwiftUI world and ChartView is the view that I actually draw on.
RestRequest gets the data from the network correctly and PlotView has access to it with no issues. When the data is received a ChartViewRepresentable is created and it contains the data, and ChartViewRepresentable creates a ChartView with the data and the data is stored in its data property correctly.
There are two problems: 1) the view's draw method never gets called when the data is loaded, and 2) if the view is redrawn a new ChartViewRepresentable (with a new ChartView) is created by SwiftUI but with no data.
I have connected the RestRequest @StateObject in every possible way imaginable, using @Binding, using @State, with no luck so far, so I'm discounting it as the problem, but with SwiftUI who really knows. It doesn't matter how I load the data, even loading the data manually into ChartView, it never calls the draw method on its own when receiving the data, and then when I for example resize the window to force a draw call it does call the draw method but on a new ChartViewRepresentable struct with no data in it.
What am I doing wrong? This is all the code besides the RestRequest() struct which I know works because I have been using it reliably on other views until now. Any clue or even a hint would be greatly appreciated.
struct PlotView: View {
@StateObject var request = RestRequest()
var body: some View {
Group {
ChartViewRepresentable(data: ChartData(array: ChartData.createArray(from: request.response.data)))
.frame(minWidth: 300, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
}
.onAppear{
let params: [String: String] = [
"limit": "10",
]
request.perform(endPoint: "http://localhost:4000/api/testdata", parameters: params)
}
}
}
struct ChartViewRepresentable: NSViewRepresentable {
typealias NSViewType = ChartView
var chart: ChartView
init(data: ChartData) {
chart = ChartView(data: data)
}
func makeNSView(context: Context) -> ChartView {
return chart
}
func updateNSView(_ nsView: ChartView, context: Context) {
}
}
class ChartView: NSView {
private var data: ChartData
init(data: ChartData) {
self.data = data
print("\(data)")
super.init(frame: .zero)
wantsLayer = true
layer?.backgroundColor = .white
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ dirtyRect: NSRect) {
print("draw call - Frame: \(self.frame), Data: \(data.array.count)")
super.draw(dirtyRect)
guard let context = NSGraphicsContext.current else { return }
context.saveGraphicsState()
if data.array.count > 0 {
//detect data present on ChartView
let ctx = context.cgContext
ctx.setFillColor(NSColor.green.cgColor)
ctx.fillEllipse(in: CGRect(x: 10, y: 10, width: 10, height: 10))
}
context.restoreGraphicsState()
}
}