使用SwiftUI Charts构建交互式折线图时出现CoreGraphics API错误
SwiftUI Charts折线图CoreGraphics NaN错误排查
我用SwiftUI Charts创建LineMark折线图,功能看似正常,但绘制每个数据点时控制台都会输出错误:
Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored. Please fix this problem.
已在Scheme中开启回溯,但无法理解输出内容。经排查,问题出在图表的交互功能上——当简化为仅基础折线图代码时,错误消失。
完整图表代码
private var chart: some View { Chart(viewModel.weatherArray, id: \.DATETIME) { LineMark( x: .value("Date", $0.DATETIME), y: .value("Temp", $0.TMP) ) .lineStyle(StrokeStyle(lineWidth: lineWidth)) .foregroundStyle(chartColor.gradient) // .interpolationMethod(interpolationMethod.mode) .symbol(Circle().strokeBorder(lineWidth: lineWidth)) .symbolSize(showSymbols ? 60 : 0) } // 图表叠加层通过点击手势确定选中的元素 .chartOverlay { proxy in GeometryReader { geo in Rectangle().fill(.clear).contentShape(Rectangle()) .gesture( SpatialTapGesture() .onEnded { value in let element = findElement(location: value.location, proxy: proxy, geometry: geo) if selectedElement?.DATETIME == element?.DATETIME { // 点击同一元素时清除选中状态 selectedElement = nil } else { selectedElement = element } } .exclusively( before: DragGesture() .onChanged { value in selectedElement = findElement(location: value.location, proxy: proxy, geometry: geo) } ) ) } } .chartBackground { proxy in ZStack(alignment: .topLeading) { GeometryReader { geo in // showLollipop是开关,留着更简单 if showLollipop, let selectedElement { let dateInterval = Calendar.current.dateInterval(of: .hour, for: selectedElement.DATETIME)! let startPositionX1 = proxy.position(forX: dateInterval.start) ?? 0 let lineX = startPositionX1 + geo[proxy.plotAreaFrame].origin.x let lineHeight = geo[proxy.plotAreaFrame].maxY let boxWidth: CGFloat = 100 let boxOffset = max(0, min(geo.size.width - boxWidth, lineX - boxWidth / 2)) // 定义棒棒糖样式 // 棒棒糖杆 Rectangle() .fill(.red) .frame(width: 2, height: lineHeight) .position(x: lineX, y: lineHeight / 2) // 棒棒糖头部 VStack(alignment: .center) { Text("\(selectedElement.DATETIME, format: .dateTime.year(.twoDigits).month(.twoDigits).day().hour())") .font(.callout) .foregroundStyle(.secondary) Text("\(selectedElement.TMP, format: .number) °C") .font(.title2.bold()) .foregroundColor(.primary) } // 棒棒糖头部背景 .background { ZStack { RoundedRectangle(cornerRadius: 8) .fill(.background) RoundedRectangle(cornerRadius: 8) .fill(.quaternary.opacity(0.7)) } .padding(.horizontal, -8) .padding(.vertical, -4) } .offset(x: boxOffset) } } } } } // 为标签查找数据的函数 func findElement(location: CGPoint, proxy: ChartProxy, geometry: GeometryProxy) -> WeatherForecastClass? { let data = viewModel.weatherArray let relativeXPosition = location.x - geometry[proxy.plotAreaFrame].origin.x if let date = proxy.value(atX: relativeXPosition) as Date? { // 查找最接近的日期元素 var minDistance: TimeInterval = .infinity var index: Int? = nil for weatherDataIndex in data.indices { let nthWeatherDataDistance = data[weatherDataIndex].DATETIME.distance(to: date) if abs(nthWeatherDataDistance) < minDistance { minDistance = abs(nthWeatherDataDistance) index = weatherDataIndex } } if let index { return data[index] } } return nil }
回溯信息
Backtrace: <CGPathAddLineToPoint+78> <$sSo16CGMutablePathRefa12CoreGraphicsE4move2to9transformySo7CGPointV_So17CGAffineTransformVtFTm+113> <_Charts_getAxisMarkWitnessTable+3021427> <_Charts_getAxisMarkWitnessTable+3022243> <_Charts_getAxisMarkWitnessTable+3022291> <__CGPathApplyWithBlock_block_invoke+63> <_ZNK2CG4Path5applyEU13block_pointerFv17CGPathElementTypePK7CGPointPbE+246> <CGPathApplyWithBlock+114> <_Charts_getAxisMarkWitnessTable+3016835> <_Charts_getAxisMarkWitnessTable+428626> <_Charts_getAxisMarkWitnessTable+464967> <__swift_memcpy33_4+28201> <_Charts_getAxisMarkWitnessTable+425557> <_Charts_getAxisMarkWitnessTable+415811> <_Charts_getAxisMarkWitnessTable+462771> <_Charts_getAxisMarkWitnessTable+416756> <_Charts_getAxisMarkWitnessTable+416214> <_Charts_getAxisMarkWitnessTable+413871> <_Charts_getAxisMarkWitnessTable+462275> <_Charts_getAxisMarkWitnessTable+416756> <_Charts_getAxisMarkWitnessTable+412741> <_Charts_getAxisMarkWitnessTable+422521> <_Charts_getAxisMarkWitnessTable+464073> <_Charts_getAxisMarkWitnessTable+417649> <_Charts_getAxisMarkWitnessTable+421314> <_Charts_getAxisMarkWitnessTable+432881> <_Charts_getAxisMarkWitnessTable+434361> <_Charts_getAxisMarkWitnessTable+434361> <_Charts_getAxisMarkWitnessTable+434361> <_Charts_getAxisMarkWitnessTable+444893> <_callVisitTableColumnType2+31236> <__swift_memcpy108_8+1328> <__swift_memcpy12_4+43911> <__swift_memcpy12_4+34396> <_callVisitTableColumnType2+30317> <block_destroy_helper.6215+63949> <_ZN2AG5Graph11UpdateStack6updateEv+537> <_ZN2AG5Graph16update_attributeENS_4data3ptrINS_4NodeEEEj+443> <_ZN2AG5Graph9value_refENS_11AttributeIDEPK15AGSwiftMetadataRh+123> <AGGraphGetValue+287> <__swift_memcpy38_4+28770> <get_witness_table 7SwiftUI19WidgetConfigurationRzAA13PreferenceKeyRd__r__lAA15Modif <get_witness_table 7SwiftUI19WidgetConfigurationRzAA13PreferenceKeyRd__r__lAA15Modi <__swift_memcpy106_8+51272> <__swift_memcpy106_8+51342> <-[UIView(CALayerDelegate) layoutSublayersOfLayer:]+2305> <_ZN2CA5Layer16layout_if_neededEPNS_11TransactionE+526> <-[UIView(Hierarchy) layoutBelowIfNeeded]+1447> <__swift_memcpy64_4+166111> <block_destroy_helper.23+59728> <block_destroy_helper.23+59750> <+[UIView(Animation) performWithoutAnimation:]+84> <__swift_memcpy64_4+161134> <block_destroy_helper.23+59728> <block_destroy_helper.23+59750> <+[UIView(Animation) performWithoutAnimation:]+84> <__swift_memcpy64_4+166410> <objectdestroy.142Tm+41107> <block_destroy_helper+36990> <block_destroy_helper+35295> <get_witness_table 7SwiftUI19WidgetConfigurationRzAA13PreferenceKeyRd__r__lAA15M <__swift_memcpy89_8+19524> <dynamic_cast_existential_0_superclass_conditional+6323> <block_destroy_helper.89+25608> <_callVisitStyleContextType2+33683> <block_destroy_helper.130+8663> <block_destroy_helper.130+8519> <-[UIViewController _setViewAppearState:isAnimating:]+1061> <-[UIViewController __viewDidAppear:]+146> <-[UINavigationController viewDidAppear:]+173> <-[UIViewController _setViewAppearState:isAnimating:]+1061> <__52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke_2+189> <__52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke+185> <__NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__+7> <-[__NSSingleObjectArrayI enumerateObjectsWithOptions:usingBlock:]+80> <-[UIViewController _setViewAppearState:isAnimating:]+2066> <__52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke_2+189> <__52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke+185> <__NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__+7> <-[__NSSingleObjectArrayI enumerateObjectsWithOptions:usingBlock:]+80> <-[UIViewController _setViewAppearState:isAnimating:]+2066> <-[UIViewController __viewDidAppear:]+146> <-[UINavigationController viewDidAppear:]+173> <-[UIViewController _setViewAppearState:isAnimating:]+1061> <-[UIViewController __viewDidAppear:]+146> <-[UIViewController _endAppearanceTransition:]+232> <-[UINavigationController navigationTransitionView:didEndTransition:fromView:toV <__49-[UINavigationController _startCustomTransition:]_block_invoke+620> <-[_UIViewControllerTransitionContext completeTransition:]+101> <__53-[_UINavigationParallaxTransition animateTransition:]_block_invoke.163+841> <__UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK__+15> <-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:]+797> <-[UIViewAnimationState sendDelegateAnimationDidStop:finished:]+190> <-[UIViewAnimationState animationDidStop:finished:]+263> <-[UIViewAnimationState animationDidStop:finished:]+648> <_ZN2CA5Layer23run_animation_callbacksEPv+318> <_dispatch_client_callout+8> <_dispatch_main_queue_drain+1463> <_dispatch_main_queue_callback_4CF+31> <__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__+9> <__CFRunLoopRun+2482> <CFRunLoopRunSpecific+560> <GSEventRunModal+139> <-[UIApplication _run]+994> <UIApplicationMain+123> <__swift_memcpy93_8+11936> <__swift_memcpy93_8+11597> <__swift_memcpy195_8+12255> <$s27SpotWx_MergeBackendFrontend0ab1_cdE3AppV5$mainyyFZ+30> <main+9> 1079162bf [Unknown process name] CGPathCloseSubpath: no current point.
简化后无错误的基础折线图代码
private var chart: some View { Chart(viewModel.weatherArray, id: \.DATETIME) { LineMark( x: .value("Date", $0.DATETIME), y: .value("Temp", $0.TMP) ) } }
内容的提问来源于stack exchange,提问作者SkimoBen
相关产品推荐
相关产品推荐

