チャートを描くためのChartViewというクラスを定義しています。
その中の変数 lastSevenRecords の中に同じクラス内で定義されたファンクション createData(completion: @escaping ([RecordData]) -> Void) 内の通信で得た結果を渡してからChartViewクラスを読み込んでもらいたいです。
その場合はどのようにすればよいでしょうか。
ChartView
1import Foundation 2import Macaw 3import Firebase 4import FirebaseFirestore 5 6class ChartView: MacawView { 7 8 static var lastSevenRecords: [RecordData] = [] 9 static let maxValue = 20 10 static let maxValueinHeight = 20 11 static let lineWidth: Double = 385 12 13 static let dataDivisor = Double(maxValue/maxValueinHeight) 14 static let adjustedData: [Double] = lastSevenRecords.map({ Double($0.score) / dataDivisor }) 15 static var animations: [Animation] = [] 16 17 required init?(coder aDecoder: NSCoder) { 18 super.init(node: ChartView.createChart(), coder: aDecoder) 19 backgroundColor = .clear 20 21 } 22 23 private static func createChart() -> Group { 24 var items: [Node] = addYAxisItems() + addXAxisItems() 25 items.append(createBars()) 26 27 return Group(contents: items, place: .identity) 28 } 29 30 private static func addYAxisItems() -> [Node] { 31 let maxLines = 10 32 let lineInterval = Int(maxValue/maxLines) 33 let yAxisHeight: Double = 600 34 let lineSpacing: Double = 60 35 36 var newNodes: [Node] = [] 37 38 for i in 1...maxLines { 39 let y = yAxisHeight - (Double(i) * lineSpacing) 40 let valueLine = Line(x1: -5, y1: y, x2: lineWidth, y2: y).stroke(fill: Color.black.with(a: 0.10)) 41 let valueText = Text(text: "(i * lineInterval)", font: Font(name: "Avenir-Light", size: 14), align: .max, baseline: .mid, place: .move(dx: -10, dy: y)) 42 valueText.fill = Color.black 43 44 45 newNodes.append(valueLine) 46 newNodes.append(valueText) 47 } 48 49 let yAxis = Line(x1: 0, y1: 0, x2: 0, y2: yAxisHeight).stroke(fill: Color.black.with(a: 0.25)) 50 newNodes.append(yAxis) 51 52 return newNodes 53 } 54 55 private static func addXAxisItems() -> [Node] { 56 let chartBaseY: Double = 600 57 var newNodes: [Node] = [] 58 59 //ここでエラーが出てしまいます 60 for i in 1...adjustedData.count { 61 let x = (Double(i) * 50) 62 let valueText = Text(text: lastSevenRecords[i - 1].recordDate!, font: Font(name: "Avenir-Light", size: 14), align: .max, baseline: .mid, place: .move(dx: x, dy: chartBaseY + 15)) 63 valueText.fill = Color.black 64 newNodes.append(valueText) 65 } 66 67 let xAxis = Line(x1: 0, y1: chartBaseY, x2: lineWidth, y2: chartBaseY).stroke(fill: Color.black.with(a: 0.25)) 68 newNodes.append(xAxis) 69 70 return newNodes 71 } 72 73 private static func createBars() -> Group { 74 let fill = LinearGradient(degree: 90, from: Color(val: 0xff4704), to: Color(val: 0xff4704).with(a: 0.33)) 75 let items = adjustedData.map { _ in Group() } 76 77 animations = items.enumerated().map { (i: Int, item: Group) in 78 item.contentsVar.animation(delay: Double(i) * 0.1) { t in 79 let height = adjustedData[i] * t * 30 80 let rect = Rect(x: Double(i) * 50 + 25, y: 600 - height, w: 30, h: height) 81 82 return [rect.fill(with:fill)] 83 } 84 } 85 86 return items.group() 87 } 88 89 static func playAnimations() { 90 animations.combine().play() 91 92 } 93 94 95 static func createData(completion: @escaping ([RecordData]) -> Void) { 96 97 //こちらで通信処理を行いDBからデータを取得する 98 //↓こちらのrecordDataArrayが得られて使いたいデータ 99 completion(recordDataArray) 100 101 } 102 } 103}
そのために以下のようにRecordViewControllerのviewDidLoad()でCompletion Handlerで得た値を渡そうと試みました。ですがChartViewクラスはこちらのviewDidLoad()に来る前に既に読み込まれてしまっていて lastSevenRecords の配列が空のまま処理を進めてしまっているので lastSevenRecords を使って定義されたadjustedDataが使われる部分で
Thread 1: Fatal error: Can't form Range with upperBound < lowerBound
とエラーが出てしまいます。ChartViewクラスが読み込まれる段階で通信結果を反映させるにはどのようにすればよいのでしょうか?
RecordViewController
1import UIKit 2 3class RecordViewController: UIViewController { 4 5 @IBOutlet private var chartView: ChartView! 6 7 override func viewDidLoad() { 8 super.viewDidLoad() 9 10 chartView.contentMode = .scaleAspectFit 11 ChartView.createData { recordDataArray in 12 13 //Completion Handlerで得られた値(recordDataArray)をChartView内のlastSevenRecordsへ 14 ChartView.lastSevenRecords = recordDataArray 15 ChartView.playAnimations() 16 17 } 18 } 19}
回答2件
あなたの回答
tips
プレビュー