简体   繁体   English

无法使用 Core Data 和 Swift 在表视图中正确保存和显示数据

[英]Cannot save and display data in table view correctly with Core Data and Swift

Goal:目标:

My goal is to pass the current minimum, average and maximum value data to table view and present them to the user.我的目标是将当前的最小值、平均值和最大值数据传递给表视图并将它们呈现给用户。

Error:错误:

When I hit the "Save" button "nan" value is passed with the current minimum, average and maximum value data.当我点击“保存”按钮时,“nan”值与当前的最小值、平均值和最大值数据一起传递。

UI screenshot界面截图

Here is the table view before pressing the Save button这是按下“保存”按钮之前的表格视图

Here is the table view after pressing the Save button这是按下保存按钮后的表格视图

Here is the current code:这是当前的代码:

Record.swift记录.swift

import Foundation
import CoreData

class Record: NSManagedObject {
    var minimumValue: Float = .nan
    var averageValue: Float = .nan
    var maximumValue: Float = .nan
}

RecordTableViewController.swift RecordTableViewController.swift

class RecordCell: UITableViewCell {
    @IBOutlet weak var maximumValueLabel: UILabel!
    @IBOutlet weak var averageValueLabel: UILabel!
    @IBOutlet weak var minimumValueLabel: UILabel!
}

class RecordTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {

    private lazy var fetchedResultsController: NSFetchedResultsController = { () -> NSFetchedResultsController<NSFetchRequestResult> in
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "History")
        let sortDescriptor: [NSSortDescriptor] = []
        fetchRequest.sortDescriptors = sortDescriptor

        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let managedObjectContext = appDelegate.persistentContainer.viewContext

        let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
        return fetchedResultsController
    }()

    let cellIdentifier: String = "cellID"
    var recordsArray = [Record]()

    override func viewDidLoad() {
        super.viewDidLoad()

        let swipe = UISwipeGestureRecognizer(target: self, action: #selector(swipeRight(_:)))
        swipe.direction = .right
        self.view.addGestureRecognizer(swipe)

        recordsArray = fetchAllRecords()
    }

    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        switch editingStyle {
        case .delete:
            let removedRecord = fetchedResultsController.object(at: indexPath) as! NSManagedObject
            let context = fetchedResultsController.managedObjectContext
            context.delete(removedRecord)

            do {
                try context.save()
                self.recordsArray.remove(at: indexPath.row)
                tableView.deleteRows(at: [indexPath], with: .fade)
            } catch _ {

            }
        default:
            break
        }
    }
}

extension RecordTableViewController {
    public func fetchAllRecords() -> [Record] {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appDelegate.persistentContainer.viewContext
        let request = NSFetchRequest<NSFetchRequestResult>(entityName: "History")
        request.returnsObjectsAsFaults = false

        do {
            let result = try context.fetch(request)
            return result as! [Record]
        } catch let error {
            fatalError(error.localizedDescription)
        }
    }
}

MainViewController.swift主视图控制器.swift

import UIKit
import Dispatch
import CoreData
import Accelerate
import Foundation
import UserNotifications

class MainViewController: UIViewController {

    var minimum: Float = .nan
    var average: Float = .nan
    var maximum: Float = .nan
    var decibel: Float = .nan

    /// MARK: Segue functions

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "saveRecord" {
            let recordVC = segue.destination as! RecordTableViewController
            let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
            let record = Record.init(entity: NSEntityDescription.entity(forEntityName: "History", in: context)!, insertInto: context)

            record.minimumValue = Float(minDbLabel.text!) ?? 0.0
            record.averageValue = Float(averageDbLabel.text!) ?? 0.0
            record.maximumValue = Float(maximumDbLabel.text!) ?? 0.0

            saveNewRecord(record: record)

            self.recordsArray.append(record)
            recordVC.recordsArray = self.recordsArray
        }
    }

    @IBAction func save(_ sender: UIButton){
        self.performSegue(withIdentifier: "saveRecord", sender: nil)
    }

    // MARK: Core Data functions

    private func saveNewRecord(record: Record) {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appDelegate.persistentContainer.viewContext

        var index: Int = 0

        let entity = NSEntityDescription.entity(forEntityName: "History", in: context)
        let newRecord = [NSManagedObject(entity: entity!, insertInto: context)] as [NSManagedObject]

        newRecord[index].setValue(record.minimumValue, forKey: "minimumValue")
        newRecord[index].setValue(record.averageValue, forKey: "averageValue")
        newRecord[index].setValue(record.maximumValue, forKey: "maximumValue")
        index += 1

        do {
            try context.save()
        } catch let error {
            print("\(error.localizedDescription)")
        }
    }
}

Any help is appreciated.任何帮助表示赞赏。

The code you provided is kinda confusing, however, here's how I setup my CoreData applications.您提供的代码有点令人困惑,但是,这是我设置 CoreData 应用程序的方法。

First: I create a CoreDataManager model第一:我创建了一个 CoreDataManager 模型
This will handle all of my Model functions like fetching viewing and context etc...这将处理我所有的模型功能,如获取查看和上下文等...

struct CoreDataManager {
  static let shared = CoreDataManager()

  let persistentContainer: NSPersistentContainer = {
    let perCon = NSPersistentContainer(name: "EntityName")
    perCon.loadPersistentStores { (storeDescription, err) in
      if let err = err {
        fatalError("\(err)")
      }
    }
    return perCon
  }()

  func fetchEntitys() -> [Entity] {
    let context = persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<Entity>(entityName: "EntityName")
    do {
      let entity = try context.fetch(fetchRequest)
      return entity
    } catch let err {
      print("\(err)")
      return []
    }
  }

  func resetEntitys() {
    let context = persistentContainer.viewContext
    let batchRequest = NSBatchDeleteRequest(fetchRequest: Entity.fetchRequest())
    do {
      try context.execute(batchRequest)
    } catch let err {
      print("\(err)")
    }
  }
}

Second: Setup your secondViewController the viewController in which you create the objects in第二:设置你的 secondViewController 你在其中创建对象的 viewController

  1. You would need to create a delegate for this viewController您需要为此 viewController 创建一个委托
protocol CreateControllerDelegate: class {
  func didAdd(entity: Entity)
}
  1. In your secondViewController in this case, it's CreateController you should add the following property.这种情况下,在您的 secondViewController中,它是 CreateController,您应该添加以下属性。
weak var delegate: CreateControllerDelegate?
  1. Implement the function in which you will save objects into your CoreData.实现将对象保存到 CoreData 中的函数。
  func createEntity() {
    let context = CoreDataManager.shared.persistentContainer.viewContext
    let entity = NSEntityDescription.insertNewObject(forEntityName: "EntityName", into: context)
    entity.setValue(nameTextField.text, forKey: "name") 
    // set all of your values that you want to be saved.
    do {
      try context.save()
      dismiss(animated: true) {
        self.delegate?.didAdd(entity: entity as! Entity)
      }
    } catch {
      let nserror = error as NSError
      fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
    }
  }

Finally, setup your firstViewController the one in which you will display all of your Core Data objects.最后,设置您的 firstViewController ,您将在其中显示所有 Core Data 对象。

  1. Add a property to your MainController in which it will hold all of your Entity objects.向 MainController 添加一个属性,它将在其中保存所有 Entity 对象。
var objectsArray = [Entity]()
  1. Inside of your MainController's viewDidLoad function add the following.在 MainController 的 viewDidLoad 函数中添加以下内容。
  override func viewDidLoad() {
    super.viewDidLoad()
    self.objectsArray = CoreDataManager.shared.fetchEntitys()
  }
  1. Confirm and implement the CreateControllerDelegate in your MainController.在 MainController 中确认并实现 CreateControllerDelegate。
extension MainController: CreateControllerDelegate {
  func didAdd(entity: Entity) {
    objectsArray.append(entity)
    let indexPath = IndexPath(row: objectsArray.count - 1, section: 0)
    tableView.insertRows(at: [indexPath], with: .automatic)
  }
}
  1. Push your secondViewController.推送您的 secondViewController。 I don't use Segues.我不使用Segues。
  @IBAction func handleAdd(_ sender: Any) {
    let createController = storyboard?.instantiateViewController(withIdentifier: "CreateController") as! CreateController
    createController.delegate = self
    let navController = UINavigationController(rootViewController: createController)
    navController.modalPresentationStyle = .fullScreen
    present(navController, animated: true)
  }

I hope this is helpful and if there's something that's not working let me know!我希望这是有帮助的,如果有什么不工作让我知道!

Good Luck!祝你好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM