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

iOS Line Chart无法显示图表条目问题求助:健身APP折线图二次进入页面后空白

解决折线图重复进入后空白的问题

看起来你遇到的问题主要是因为图表数据没有持久化存储、视图重复创建,还有几个逻辑上的小错误导致的。我帮你梳理一下问题点,然后给出修复后的方案:

问题分析

  • 每次进入都重置数据数组:在viewDidLayoutSubviews里每次都新建entries数组,没有从UserDefaults加载历史的图表条目,导致只有满足条件时才会有数据,否则数组为空,图表就空白了。
  • 重复创建LineChartView:每次viewDidLayoutSubviews都会创建新的linechart实例并添加到视图,不仅浪费资源,还可能导致旧视图被覆盖或者显示异常。
  • 时间判断错误:你用了Calendar.current.component(.minute, from: date)来获取当前小时,这其实拿到的是分钟数,应该用.hour才对,这会导致你的条件判断逻辑完全失效。
  • UserDefaults键名错误:更新小时计数时用了"daysofexerciserecorded",但你读取的是"hoursofexerciserecorded",导致计数没有正确保存。

修复方案

我们需要做这几件事:

  1. 将图表条目持久化存储,而不是每次都新建空数组
  2. 只初始化一次LineChartView,避免重复添加
  3. 修正时间判断的逻辑
  4. 修复UserDefaults的键名错误

修复后的代码

import UIKit
import Charts

class DaysViewController: UIViewController, ChartViewDelegate {
    @IBOutlet weak var graphsview: UIView!
    var linechart: LineChartView!
    
    // 用来存储历史图表条目,或者从UserDefaults加载
    private var chartEntries: [ChartDataEntry] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 只初始化一次LineChartView
        setupLineChart()
        // 从UserDefaults加载历史条目
        loadSavedEntries()
        // 检查是否需要添加新的条目
        checkAndAddNewEntry()
        // 更新图表显示
        updateChartData()
    }
    
    private func setupLineChart() {
        linechart = LineChartView(frame: graphsview.bounds)
        linechart.delegate = self
        linechart.center = graphsview.center
        graphsview.addSubview(linechart) // 添加到graphsview而不是view,避免布局混乱
    }
    
    private func loadSavedEntries() {
        // 把条目数组转换成Data存储到UserDefaults,实现持久化
        if let savedData = UserDefaults.standard.data(forKey: "chartEntries"),
           let entries = try? JSONDecoder().decode([ChartDataEntry].self, from: savedData) {
            chartEntries = entries
        }
    }
    
    private func saveEntries() {
        // 把条目数组转换成Data保存到UserDefaults
        if let data = try? JSONEncoder().encode(chartEntries) {
            UserDefaults.standard.set(data, forKey: "chartEntries")
        }
    }
    
    private func checkAndAddNewEntry() {
        let caloriesBurnt = UserDefaults.standard.double(forKey: "calories burnt today")
        var hoursRecorded = UserDefaults.standard.integer(forKey: "hoursofexerciserecorded")
        
        let date = Date()
        let calendar = Calendar.current
        let currentHour = calendar.component(.hour, from: date) // 修正为获取当前小时
        let previousHour = UserDefaults.standard.integer(forKey: "hour")
        
        // 判断当前小时是否比记录的小时大,避免重复添加条目
        if currentHour > previousHour {
            hoursRecorded += 1
            let newEntry = ChartDataEntry(x: Double(hoursRecorded), y: caloriesBurnt)
            chartEntries.append(newEntry)
            
            // 更新UserDefaults的值,统一键名
            UserDefaults.standard.set(hoursRecorded, forKey: "hoursofexerciserecorded")
            UserDefaults.standard.set(currentHour, forKey: "hour")
            
            // 保存新的条目
            saveEntries()
        }
    }
    
    private func updateChartData() {
        let set = LineChartDataSet(entries: chartEntries)
        set.colors = ChartColorTemplates.colorful()
        let data = LineChartData(dataSet: set)
        linechart.data = data
        linechart.notifyDataSetChanged() // 通知图表更新数据
    }
    
    // 处理视图布局变化时调整图表大小
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        linechart.frame = graphsview.bounds
    }
}

关键修改点说明

  • 持久化图表条目:用JSONEncoder和JSONDecoder把ChartDataEntry数组转换成Data存储到UserDefaults,这样每次进入ViewController都能加载之前的历史数据,不会丢失。
  • 单一实例的LineChartView:在viewDidLoad里只初始化一次图表,viewDidLayoutSubviews只负责调整大小,避免重复添加视图。
  • 修正时间逻辑:把获取当前时间的组件改成.hour,确保小时判断正确,只有当进入新的小时时才添加新的条目。
  • 修复键名错误:统一使用"hoursofexerciserecorded"作为小时计数的键名,确保数据正确保存和读取。
  • 分离逻辑:把图表初始化、数据加载、添加新条目、更新图表的逻辑拆分成独立的方法,代码更清晰,也更容易维护。

这样修改后,无论你多少次通过segue进入这个ViewController,折线图都会显示所有历史的卡路里消耗数据点,并且每进入新的小时会自动添加新的条目。

内容的提问来源于stack exchange,提问作者Kiran Lim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:02:41