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

Swift+Core Data无法正确保存并在Table View中展示数据

解决Core Data保存后数据出现NaN的问题

Hey,我仔细看了你提供的代码,发现几个关键问题导致保存后TableView里出现NaN值,咱们一步步来修复:

1. Record类的Core Data属性声明错了!

你现在的Record类直接声明了存储属性,还默认设成了.nan,但Core Data的实体属性必须用@NSManaged修饰,这样才能和数据模型里的属性绑定,不然Core Data根本不会持久化这些值,读取的时候自然还是初始的NaN。

修改后的Record类应该是这样:

import Foundation
import CoreData

class Record: NSManagedObject {
    @NSManaged var minimumValue: Float
    @NSManaged var averageValue: Float
    @NSManaged var maximumValue: Float
}

别忘了检查你的.xcdatamodeld文件里的History实体,要确保已经添加了这三个Float类型的属性,并且把实体的类名设置为Record哦。

2. saveNewRecord方法在做无用功,还搞乱了数据

你在prepare(for:sender:)里已经创建了record对象并插入到上下文了,但saveNewRecord里又重新创建了一个空的NSManagedObject数组,这完全是多余的,反而导致你之前赋值的record没被正确处理,最终存到Core Data里的是空值,读取时就变成了NaN。

把saveNewRecord改成这样就行:

private func saveNewRecord(record: Record) {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    do {
        try context.save()
    } catch let error {
        print("保存数据失败:\(error.localizedDescription)")
    }
}

3. TableView的数据逻辑可以更靠谱

你现在手动维护recordsArray,不如直接用NSFetchedResultsController来自动获取和刷新数据,这样数据变更时TableView能自动更新,还不容易出错。

先修改RecordTableViewController里的FRC:

private lazy var fetchedResultsController: NSFetchedResultsController<Record> = {
    // 用自动生成的fetchRequest,比手动写更安全
    let fetchRequest = Record.fetchRequest()
    // 加个排序规则,比如按最小值升序,不然数据顺序会乱
    let sortDescriptor = NSSortDescriptor(key: "minimumValue", ascending: true)
    fetchRequest.sortDescriptors = [sortDescriptor]
    
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let managedObjectContext = appDelegate.persistentContainer.viewContext
    let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
    frc.delegate = self
    return frc
}()

然后在viewDidLoad里执行fetch:

override func viewDidLoad() {
    super.viewDidLoad()
    let swipe = UISwipeGestureRecognizer(target: self, action: #selector(swipeRight(_:)))
    swipe.direction = .right
    self.view.addGestureRecognizer(swipe)
    
    // 执行FRC的fetch操作,获取初始数据
    do {
        try fetchedResultsController.performFetch()
    } catch {
        print("获取数据失败:\(error.localizedDescription)")
    }
}

再修改TableView的数据源方法,直接用FRC的数据:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return fetchedResultsController.sections?[section].numberOfObjects ?? 0
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! RecordCell
    let record = fetchedResultsController.object(at: indexPath)
    
    // 额外加个安全处理,如果真的出现NaN,显示0.0代替
    cell.minimumValueLabel.text = record.minimumValue.isNaN ? "0.0" : String(format: "%.2f", record.minimumValue)
    cell.averageValueLabel.text = record.averageValue.isNaN ? "0.0" : String(format: "%.2f", record.averageValue)
    cell.maximumValueLabel.text = record.maximumValue.isNaN ? "0.0" : String(format: "%.2f", record.maximumValue)
    
    return cell
}

4. 文本转Float的地方加个安全防护

在prepare(for:sender:)里,从Label转Float的时候,最好先处理一下空文本的情况,避免因为Label为空导致转换失败:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "saveRecord" {
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        // 用Record.entity()来创建对象,比手动写实体名更安全
        let record = Record(entity: Record.entity(), insertInto: context)
        
        // 安全转换文本为Float,空文本的话默认设为0.0
        record.minimumValue = Float(minDbLabel.text ?? "") ?? 0.0
        record.averageValue = Float(averageDbLabel.text ?? "") ?? 0.0
        record.maximumValue = Float(maximumDbLabel.text ?? "") ?? 0.0
        
        saveNewRecord(record: record)
        // 现在不需要手动维护recordsArray了,FRC会自动获取最新数据
    }
}

最后总结一下

最核心的问题就是Record类的属性没有正确绑定Core Data实体,导致数据根本没被正确持久化,再加上重复创建Core Data对象的操作,才出现了NaN值。按照上面的步骤修改后,应该就能正常保存和展示数据啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 14:03:13