swift - 使用 NSFetchRequest 从 CoreData 填充 TableView

标签 swift xcode uitableview core-data nsfetchrequest

我需要用我的核心数据中的数据填充我的 TableView 。 我可以显示我的行,但是我无法填充我的表格 View ! 我使用 Swift 3 和 Xcode 8。 这是我的代码,在这个 Controller 中我必须显示列表。

class iTableViewController: UITableViewController, NSFetchedResultsControllerDelegate{
@IBOutlet var iTableView: UITableView!


override func viewDidLoad(){
    super.viewDidLoad()

    iTableView.dataSource = self
    iTableView.delegate = self

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let managerContext = appDelegate.persistentContainer.viewContext
    let interventsFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Intervento")

    do{
        //results
        let fetchedIntervents = try managerContext.fetch(interventsFetch) as! [Intervento]

        for interv in fetchedIntervents{
            print(interv.stampRow())
        }

        NSLog(String(fetchedIntervents.count))
    }catch{
        fatalError("Failed to fetch employees: \(error)")
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

//number of sections
override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

//numer of rows
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
}

//cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell")

    cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator

    //print the example cell
    cell.textLabel?.text = "title"
    cell.detailTextLabel?.text = "subtitle"
    return cell
}

//swipe and delete
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
    if(editingStyle == UITableViewCellEditingStyle.delete){
        //TODO
    }
}

// click cell
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
    performSegue(withIdentifier: "segueDetail", sender: self)
}


override func viewDidAppear(_ animated: Bool){
    //iTableView.reloadData()
}

override func viewWillDisappear(_ animated: Bool) {
    //iTableView.reloadData()
    //fetchData()
}
}

这是我的类(class)

extension Intervento {

@nonobjc public class func fetchRequest() -> NSFetchRequest<Intervento> {
    return NSFetchRequest<Intervento>(entityName: "Intervento");
}

@NSManaged public var cliente: Int32
@NSManaged public var dataFine: String?
@NSManaged public var dataInizio: String?
@NSManaged public var descrizione: String?
@NSManaged public var foto: String?
@NSManaged public var id: Int32
@NSManaged public var stato: String?
@NSManaged public var tecnico: String?

func stampRow()->String{
    let v1 = String(id) + " " + String(cliente) + " "
    let v2 = dataInizio! + " " + dataFine! + " "
    let v3 = stato! + " " + tecnico! + " " + descrizione!
    return v1 + v2 + v3
}
}

这是我保存数据的代码(有效)

 @IBAction func addButton(_ sender: Any){
    //genero la data
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
    let strDate = dateFormatter.string(from: myDatePicker.date)

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let managerContext = appDelegate.persistentContainer.viewContext
    let newInt = NSEntityDescription.insertNewObject(forEntityName: "Intervento", into: managerContext)

    newInt.setValue(1, forKey: "id")
    newInt.setValue(strDate, forKey: "dataInizio")
    newInt.setValue("", forKey: "dataFine")
    newInt.setValue(2, forKey: "cliente")
    newInt.setValue("Matt", forKey: "tecnico")
    newInt.setValue(stato[1], forKey: "stato")
    newInt.setValue("", forKey: "descrizione")
    newInt.setValue("", forKey: "foto")

    do{
        try managerContext.save()
        print("saved")
    }catch let error as NSError{
        //errore salvataggio
        print("Could not fetch \(error), \(error.userInfo)")
    }
}

最佳答案

首先,你的类应该实现这个协议(protocol):

UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate

您可以使用以下代码从持久存储中加载数据:

//load data

//persistant container
let persistentContainer = NSPersistentContainer.init(name: "Model")

//
lazy var fetchedResultsController: NSFetchedResultsController<Intervento> = {
    // Create Fetch Request
    let fetchRequest: NSFetchRequest<Intervento> = Intervento.fetchRequest()

    // Configure Fetch Request
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "dataInizio", ascending: false)]

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

    // Create Fetched Results Controller
    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managerContext, sectionNameKeyPath: nil, cacheName: nil)

    // Configure Fetched Results Controller
    fetchedResultsController.delegate = self

    return fetchedResultsController
}()

//carica
func load(){
    //persistant container
    persistentContainer.loadPersistentStores { (persistentStoreDescription, error) in
        if let error = error {
            print("Unable to Load Persistent Store")
            print("\(error), \(error.localizedDescription)")
        } else { 
            do {
                try self.fetchedResultsController.performFetch()
            } catch {
                let fetchError = error as NSError
                print("Unable to Perform Fetch Request")
                print("\(fetchError), \(fetchError.localizedDescription)")
            }

        }
    }
}

override func viewDidLoad(){
    super.viewDidLoad()

    iTableView.delegate = self
    iTableView.dataSource = self

    // trigger load
    load()
}

你的数据将被获取并显示出来,因为你已经通过这行代码委托(delegate)了 iTableViewController:

// Configure Fetched Results Controller
fetchedResultsController.delegate = self

为了使它工作,你的 ViewController 必须符合 NSFetchedResultsControllerDelegate 协议(protocol),在这里你可以找到一个可能的实现:

extension iTableViewController: NSFetchedResultsControllerDelegate {

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    iTableView.beginUpdates()
}

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    iTableView.endUpdates()
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch (type) {
    case .insert:
        if let indexPath = newIndexPath {
            iTableView.insertRows(at: [indexPath], with: .fade)
        }
        break;
    case .delete:
        if let indexPath = indexPath {
            iTableView.deleteRows(at: [indexPath], with: .fade)
        }
        break;
    case .update:
        if let indexPath = indexPath, let cell = iTableView.cellForRow(at: indexPath) {
            configureCell(cell, at: indexPath)
        }
        break;
    case .move:
        if let indexPath = indexPath {
            iTableView.deleteRows(at: [indexPath], with: .fade)
        }

        if let newIndexPath = newIndexPath {
            iTableView.insertRows(at: [newIndexPath], with: .fade)
        }
        break;
    }
}
}

总而言之,这是您的 iTableViewController 的完整实现(我还包含了删除行的必要代码):

class iTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
@IBOutlet var iTableView: UITableView!

//load data

//persistant container
let persistentContainer = NSPersistentContainer.init(name: "Model")

//
lazy var fetchedResultsController: NSFetchedResultsController<Intervento> = {
    // Create Fetch Request
    let fetchRequest: NSFetchRequest<Intervento> = Intervento.fetchRequest()

    // Configure Fetch Request
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "dataInizio", ascending: false)]

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

    // Create Fetched Results Controller
    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managerContext, sectionNameKeyPath: nil, cacheName: nil)

    // Configure Fetched Results Controller
    fetchedResultsController.delegate = self

    return fetchedResultsController
}()

//carica
func load(){
    //persistant container
    persistentContainer.loadPersistentStores { (persistentStoreDescription, error) in
        if let error = error {
            print("Unable to Load Persistent Store")
            print("\(error), \(error.localizedDescription)")
        } else {
            do {
                try self.fetchedResultsController.performFetch()
            } catch {
                let fetchError = error as NSError
                print("Unable to Perform Fetch Request")
                print("\(fetchError), \(fetchError.localizedDescription)")
            }

        }
    }
}


override func viewDidLoad(){
    super.viewDidLoad()

    iTableView.delegate = self
    iTableView.dataSource = self

    // trigger load
    load()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

//numero di sezioni
func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

//numero di righe
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    guard let quotes = fetchedResultsController.fetchedObjects else { return 0 }
    return quotes.count
}

//gestisco la cella
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //genero la cella
    let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell")

    configureCell(cell, at:indexPath)
    return cell
}

//swipe and delete
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
    if(editingStyle == .delete){

        // Fetch Quote
        let quote = fetchedResultsController.object(at: indexPath)

        // Delete Quote
        quote.managedObjectContext?.delete(quote)
    }
}

// click cell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
    performSegue(withIdentifier: "segueDetail", sender: self)
}


func configureCell(_ cell: UITableViewCell, at indexPath: IndexPath) {

    //get intervento
    let intervento = fetchedResultsController.object(at: indexPath)

    //fill the cell
    cell.textLabel?.text = intervento.dataInizio
    cell.detailTextLabel?.text = "SOME_THING"
}

//quando appare aggiorno la table view
override func viewDidAppear(_ animated: Bool){
    self.iTableView.reloadData()
}
}

extension iTableViewController: NSFetchedResultsControllerDelegate {

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    iTableView.beginUpdates()
}

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    iTableView.endUpdates()
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch (type) {
    case .insert:
        if let indexPath = newIndexPath {
            iTableView.insertRows(at: [indexPath], with: .fade)
        }
        break;
    case .delete:
        if let indexPath = indexPath {
            iTableView.deleteRows(at: [indexPath], with: .fade)
        }
        break;
    case .update:
        if let indexPath = indexPath, let cell = iTableView.cellForRow(at: indexPath) {
            configureCell(cell, at: indexPath)
        }
        break;
    case .move:
        if let indexPath = indexPath {
            iTableView.deleteRows(at: [indexPath], with: .fade)
        }

        if let newIndexPath = newIndexPath {
            iTableView.insertRows(at: [newIndexPath], with: .fade)
        }
        break;
    }
}
}

在对数据进行操作时(例如添加新数据时),不要忘记始终使用相同的上下文。

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

有关完整示例,您应该查看此处:https://github.com/bartjacobs/ExploringTheFetchedResultsControllerDelegateProtocol

关于swift - 使用 NSFetchRequest 从 CoreData 填充 TableView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42676625/

相关文章:

swift - 无法从 UserDefaults Swift 检索日期对象

iphone - 通过Xcode运行Iphone应用程序与通过Iphone运行它之间的区别

ios - 这是 iOS 的错误吗?

ios - 如何从不同的类重新加载我的表?

iphone - 如何用图像填充组 TableView 单元格

ios - 呈现不同的局部 View iOS Swift

swift - Cocoa:在 CGEvent 中模拟 Command+Tab

ios - 当我执行 segue 到 ViewController 时,圆圈已经填满

swift - NSDocumentController.openDocument 不允许选择自定义文件类型

ios - NSAttributedString绘图-多少行?