如何通过UserDefaults持久化Bar Chart数据避免启动时图表空白
Got it, let's work through fixing this Bar Chart data persistence issue step by step. The main problem with your current setup is that you've got the encoding part mostly right, but the decoding logic is incomplete—and we also need to make sure we're handling edge cases properly with modern Swift APIs.
First, a quick check: the BarChartData, BarChartDataSet, and ChartDataEntry classes from the Charts framework all conform to NSCoding, so we can safely use archiving/unarchiving to save and load them.
1. 完善的编码(存储)代码
Your original storage code is close, but we can add error handling and use the more modern archiving API (safer for iOS 12+):
// Assume you've already created your ChartDataEntry objects (entry1-entry4) let chartEntries = [entry1, entry2, entry3, entry4] let dataSet = BarChartDataSet(values: chartEntries, label: "Widgets Type") let barChartData = BarChartData(dataSets: [dataSet]) // Archive and save the data do { let encodedData = try NSKeyedArchiver.archivedData( withRootObject: barChartData, requiringSecureCoding: false ) UserDefaults.standard.set(encodedData, forKey: "SavedBarChartData") // Note: You don't need to call synchronize() anymore on iOS 10+ — it's handled automatically } catch { print("Oops, failed to encode chart data: \(error.localizedDescription)") }
2. 完整的解码(读取)代码
This is the part you were missing. We need to safely unarchive the data and cast it back to BarChartData:
func loadSavedBarChartData() -> BarChartData? { // Check if there's saved data first guard let encodedData = UserDefaults.standard.data(forKey: "SavedBarChartData") else { print("No saved chart data found") return nil } do { // Unarchive and cast to BarChartData guard let decodedData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(encodedData) as? BarChartData else { print("Couldn't convert decoded data to BarChartData") return nil } return decodedData } catch { print("Failed to decode chart data: \(error.localizedDescription)") return nil } }
3. 使用示例(在你的ViewController中)
Add this to your view controller to load saved data on app launch, or fall back to default data if none exists:
// Make sure you have an IBOutlet connected to your BarChartView @IBOutlet weak var barChartView: BarChartView! override func viewDidLoad() { super.viewDidLoad() if let savedChartData = loadSavedBarChartData() { // Load the saved data into the chart barChartView.data = savedChartData barChartView.notifyDataSetChanged() // Refresh the chart to show the data } else { // No saved data — create default data and save it let defaultEntries = [ ChartDataEntry(x: 0, y: 7), ChartDataEntry(x: 1, y: 15), ChartDataEntry(x: 2, y: 10), ChartDataEntry(x: 3, y: 22) ] let defaultDataSet = BarChartDataSet(values: defaultEntries, label: "Widgets Type") let defaultChartData = BarChartData(dataSets: [defaultDataSet]) // Set default data to the chart barChartView.data = defaultChartData // Save the default data for next launch do { let encodedData = try NSKeyedArchiver.archivedData( withRootObject: defaultChartData, requiringSecureCoding: false ) UserDefaults.standard.set(encodedData, forKey: "SavedBarChartData") } catch { print("Failed to save default chart data: \(error.localizedDescription)") } } }
Quick Notes
- If you've customized your chart's style (like bar colors, text fonts, etc.), those will be saved along with the data—so your chart will look the same on the next launch.
- Always handle errors during encoding/decoding to avoid crashes if something goes wrong (e.g., corrupted saved data).
- The key name ("SavedBarChartData") should be consistent between encoding and decoding—typos here are a common mistake!
内容的提问来源于stack exchange,提问作者dpathik

