You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 23:05:27