我有三个视图控制器(两个UIViewControllers和1个​​UITableViewController)。我想在tableView上显示所有数据,并在两个单独的视图控制器上添加/更新数据。

两个UIViewControllers每个都有三个textField(用于名称,电子邮件和电话号码)和一个按钮,用于保存/更新CoreData中和tableViewController上的数据。

表格视图中的一个部分由三行/两行组成(数字文本字段可以为空)。在某节中刷行时,用户可以删除整个节或编辑该节中的数据。

我创建了“人”实体和三个属性(“名称”,“电子邮件”,“数字”,所有均为String数据类型)。

但是我在网上遇到以下错误

    let objectUpdate = test[0] as! NSManagedObject


错误:致命错误:索引超出范围

import UIKit
import CoreData

class RootTableViewController: UITableViewController {

//Array to display the data in table:

var array_of_person_data_array : [PersonData] = []

//Variable with index of selected row/section:

var index = 0

override func viewDidLoad() {
    super.viewDidLoad()

    let rightBarButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(nextScreen))

    navigationItem.rightBarButtonItem = rightBarButton

    tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "reuseIdentifier")

}

override func viewWillAppear(_ animated: Bool) {
    retrieveData()
    tableView.reloadData()
}

// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int {
    return array_of_person_data_array.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if array_of_person_data_array[section].number == nil || array_of_person_data_array[section].number == ""
    {return 2}
    return 3
}


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! TableViewCell

    if indexPath.row == 0
    {cell.personLabel.text = array_of_person_data_array[indexPath.section].name}
    else if indexPath.row == 1
    {cell.personLabel.text = array_of_person_data_array[indexPath.section].email}
    else
    {cell.personLabel.text = array_of_person_data_array[indexPath.section].number}



    return cell
}



//Row actions when swiped:

override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

    index = indexPath.section


    //Cancel row action:

    let cancelRowAction = UITableViewRowAction(style: .normal, title: "Cancel", handler: {(action : UITableViewRowAction,indexPath : IndexPath) in

    })


    //Update row action:

    let updateRowAction = UITableViewRowAction(style: .default, title: "Update", handler: {(action: UITableViewRowAction, indexPath: IndexPath) in


        let sbObj = UIStoryboard(name: "Main", bundle: nil)
        let svcObj = sbObj.instantiateViewController(withIdentifier: "UpdateViewControllerSB") as! UpdateViewController
        svcObj.index = self.index
        svcObj.personDataObject = self.array_of_person_data_array[indexPath.section]
        self.navigationController?.pushViewController(svcObj, animated: true)

    })


    //Delete row action:

    let deleteRowAction = UITableViewRowAction(style: .destructive, title: "Delete", handler: {(alert : UITableViewRowAction, indexPath : IndexPath) in

        //Delete controller:

        let deleteController = UIAlertController(title: "Delete", message: nil, preferredStyle: .actionSheet)

        //Delete action:

        let deleteAction = UIAlertAction(title: "Delete", style: .destructive, handler: {(UIAlertAction)in
            self.deleteData()
        })

        deleteController.addAction(deleteAction)

        //Cancel action:

        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

        deleteController.addAction(cancelAction)


        //Present the controller:

        self.present(deleteController,animated: true,completion: nil)

    })

    return [cancelRowAction,updateRowAction,deleteRowAction]
}


override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let view = UIView(frame: CGRect(x: 0, y: 0, width: 1000, height: 1000))
    return view
}

@objc func nextScreen()
{
    let sbObj = UIStoryboard(name: "Main", bundle: nil)
    let svcObj = sbObj.instantiateViewController(withIdentifier: "AddViewControllerSB") as! AddViewController
    self.navigationController?.pushViewController(svcObj, animated: true)
}




//Function to retrieve data from core data:

func retrieveData() {

    //As we know that container is set up in the AppDelegates so we need to refer that container.
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }

    //We need to create a context from this container
    let managedContext = appDelegate.persistentContainer.viewContext

    //Prepare the request of type NSFetchRequest  for the entity
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")

    //        fetchRequest.fetchLimit = 1
    //        fetchRequest.predicate = NSPredicate(format: "username = %@", "Ankur")
    //        fetchRequest.sortDescriptors = [NSSortDescriptor.init(key: "email", ascending: false)]
    //
    do {
        let result = try managedContext.fetch(fetchRequest)
        for data in result as! [NSManagedObject] {


            array_of_person_data_array.append(PersonData(personName: data.value(forKey: "name") as! String, personEmail: data.value(forKey: "email") as! String, personNumber: data.value(forKey: "number") as? String))

        }

    } catch {

        print("Failed")
    }
}



//Function to delete data from Core Data:
func deleteData(){

    //As we know that container is set up in the AppDelegates so we need to refer that container.
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }

    //We need to create a context from this container
    let managedContext = appDelegate.persistentContainer.viewContext

    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
    fetchRequest.predicate = NSPredicate(format: "name = %@", array_of_person_data_array[index].name!)
    fetchRequest.predicate = NSPredicate(format: "email = %@", array_of_person_data_array[index].email!)
    fetchRequest.predicate = NSPredicate(format: "number = %@", array_of_person_data_array[index].number!)



    do
    {
        let test = try managedContext.fetch(fetchRequest)

        let objectToDelete = test[0] as! NSManagedObject
        managedContext.delete(objectToDelete)
        array_of_person_data_array.remove(at: index)

        do{
            try managedContext.save()
        }
        catch
        {
            print(error)
        }

    }
    catch
    {
        print(error)
    }
    tableView.reloadData()
}

}


添加视图控制器:

import UIKit
import CoreData

class AddViewController: UIViewController {

@IBOutlet weak var nameTF: UITextField!

@IBOutlet weak var emailTF: UITextField!

@IBOutlet weak var numberTF: UITextField!


override func viewDidLoad() {
    super.viewDidLoad()

}

@IBAction func addButtonAction(_ sender: Any) {

    createData()

    navigationController?.popToRootViewController(animated: true)

}


func createData(){

    //As we know that container is set up in the AppDelegates so we need to refer that container.
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }

    //We need to create a context from this container
    let managedContext = appDelegate.persistentContainer.viewContext

    //Now let’s create an entity and new user records.
    let userEntity = NSEntityDescription.entity(forEntityName: "Person", in: managedContext)!

    //Get data ready to be set into CORE DATA:

    let user = NSManagedObject(entity: userEntity, insertInto: managedContext)
    user.setValue(nameTF.text, forKeyPath: "name")
    user.setValue(emailTF.text, forKey: "email")
    user.setValue(numberTF.text, forKey: "number")


    //Save the set data to CORE DATA:

    do {
        try managedContext.save()

    } catch let error as NSError {
        print("Could not save. \(error), \(error.userInfo)")
    }
}

}


更新视图控制器:

class UpdateViewController: UIViewController {

@IBOutlet weak var nameTF: UITextField!

@IBOutlet weak var emailTF: UITextField!

@IBOutlet weak var numberTF: UITextField!

var index : Int?

var personDataObject=PersonData(personName: "sample", personEmail: "sample@sample", personNumber: "xxxx-xxx-xxx")

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

@IBAction func updateButtonAction(_ sender: Any) {

    self.updateData()
    navigationController?.popToRootViewController(animated: true)

}




//Update the data in CoreData:

func updateData(){

    //As we know that container is set up in the AppDelegates so we need to refer that container.
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }

    //We need to create a context from this container
    let managedContext = appDelegate.persistentContainer.viewContext

    let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "Person")
    fetchRequest.predicate = NSPredicate(format: "name = %@", "Ankur1")
    fetchRequest.predicate = NSPredicate(format: "email = %@", "Ankur1")
    fetchRequest.predicate = NSPredicate(format: "number = %@", "Ankur1")


    do
    {
        let test = try managedContext.fetch(fetchRequest)

        let objectUpdate = test[0] as! NSManagedObject

        objectUpdate.setValue(nameTF.text, forKey: "name")
        objectUpdate.setValue(emailTF.text, forKey: "email")
        if let no = numberTF.text
        {objectUpdate.setValue(no, forKey: "number")}
        do{
            try managedContext.save()
        }
        catch
        {
            print(error)
        }
    }
    catch
    {
        print(error)
    }

}
}


PersonData类定义为:

class PersonData
{
var name : String?
var email: String?
var number : String?

init(personName : String, personEmail : String, personNumber : String?) {
    name = personName
    email = personEmail
    number = personNumber
 }
 }


如何更新现有数据或将新数据添加到CoreData并在Table View Controller上显示新数据?

最佳答案

您应该查看NSFetchedResultsController:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/nsfetchedresultscontroller.html

本质上,您想在CoreData上下文的第二个屏幕上创建/更新/删除值,保存这些更改,然后在主屏幕上设置获取的结果控制器(通过遵循上述文档)以自动侦听这些更改并将它们反映在表格中

这是一个好习惯,因为您不必担心自己更新视图并保持状态同步-视图更新时视图自动检索数据,这是自动完成的。

关于ios - 如何在第二屏幕上更新存储在核心数据中的值,并在第一屏幕上显示更新的值?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57482742/

10-14 22:10
查看更多