【问题标题】:CoreData - PickerView updating a tableViewCoreData - PickerView 更新 tableView
【发布时间】:2015-08-25 02:58:05
【问题描述】:

看这段代码:

型号:

import Foundation
import CoreData

class TrainingDetails: NSManagedObject {

    @NSManaged var exerciseName: String
    @NSManaged var repsNumber: String
    @NSManaged var setsNumber: String
    @NSManaged var trainingDay: TrainingDay

}

import Foundation
import CoreData

class TrainingDay: NSManagedObject {

    @NSManaged var day: String
    @NSManaged var dayIndex: NSNumber
    @NSManaged var trainingDetails: NSSet

}

这个功能在这里

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

        let currentDay = daysArray[row]

        let fetchRequest = NSFetchRequest(entityName: "TrainingDetails")
        let predicate = NSPredicate(format: "trainingDay.day == %@", currentDay)
        fetchRequest.predicate = predicate
        let sort = NSSortDescriptor(key: "exerciseName", ascending: true)
        fetchRequest.sortDescriptors = [sort]
        detailsArray = (moc!.executeFetchRequest(fetchRequest, error: nil) as? [TrainingDetails])!
        exerciseTableView.reloadData()
    }

现在,如您所见,我有一个pickerView,每当我在其中选择一个不同的选项时,它应该更新一个tableView,但这并没有发生。我知道不是 let currentDay = daysArray[row] 我应该将 CoreData 中的 fetchedResultsController 归因于 currentDay,然后尝试更新 tableView。

我的问题是:我这样想是对的吗?我该怎么做?

我是 Swift 的新手,我希望有一些关于如何操作的示例。

提前致谢!!

更新 -> 完整代码

import UIKit
import CoreData

class ExerciseViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIPickerViewDataSource, UIPickerViewDelegate, NSFetchedResultsControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        VDL()

        //sets stepper configs
        setsStepper.wraps = false
        setsStepper.autorepeat = true
        setsStepper.continuous = true
        setsStepper.tintColor = UIColor.redColor()
        setsStepper.minimumValue = 0
        setsStepper.maximumValue = 500
        setsStepper.value = 0

        //reps stepper configs
        repsStepper.wraps = false
        repsStepper.autorepeat = true
        repsStepper.continuous = true
        repsStepper.tintColor = UIColor.orangeColor()
        repsStepper.minimumValue = 0
        repsStepper.maximumValue = 500
        repsStepper.value = 0

        exerciseTableView.reloadData()
    }

    var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
    var fetchedResultsController: NSFetchedResultsController?

    @IBOutlet var exerciseTableView: UITableView!

    @IBOutlet var daysPickerView: UIPickerView!

    @IBOutlet var exerciseName: UITextField!
    @IBOutlet var setsStepper: UIStepper!
    @IBOutlet var repsStepper: UIStepper!

    @IBOutlet var setsNumber: UILabel!
    @IBOutlet var repsNumber: UILabel!

    var daysArray = [TrainingDay]()
    var detailsArray = [TrainingDetails]()

    func VDL () {

        let fetchRequest = NSFetchRequest(entityName: "TrainingDay")
        let sort = NSSortDescriptor(key: "dayIndex", ascending: true)
        fetchRequest.sortDescriptors = [sort]
        daysArray = (moc!.executeFetchRequest(fetchRequest, error: nil) as? [TrainingDay])!
        if daysArray.count == 0 { // nothing there
            let dayEntity = NSEntityDescription.entityForName("TrainingDay", inManagedObjectContext: moc!)
            let days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
            for (index, name) in enumerate(days) {
                let newDay = TrainingDay(entity: dayEntity!, insertIntoManagedObjectContext: moc)
                newDay.day = name
                newDay.dayIndex = index
                daysArray.append(newDay)
                println("NAME: \(newDay.day) INDEX: \(newDay.dayIndex)")
            }
            var error: NSError?
            moc!.save(&error)
        }
    }


    func appendTrainingDetailsToArray () {
        let row = daysPickerView.selectedRowInComponent(0)
        let currentDay = daysArray[row]

        let detailsEntity = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
        let trainingdetails = TrainingDetails(entity: detailsEntity!, insertIntoManagedObjectContext: moc)
        trainingdetails.exerciseName = exerciseName.text
        trainingdetails.repsNumber = repsNumber.text!
        trainingdetails.setsNumber = setsNumber.text!
        trainingdetails.trainingDay = currentDay

        var error: NSError?
        moc?.save(&error)

        if let err = error {
            var status = err.localizedFailureReason
            println("\(status)")
        } else {
            println("CURRENT SETTING: \(trainingdetails.trainingDay)")
        }
    }

    func fetchTrainingDetails() -> NSFetchRequest {

        let fetchRequest = NSFetchRequest(entityName: "TrainingDetails")
        fetchRequest.predicate = nil
        let sortDescriptor = NSSortDescriptor(key: "trainingDay", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]
        fetchRequest.fetchBatchSize = 20
        return fetchRequest
    }

    @IBAction func doneButton(sender: AnyObject) {
        appendTrainingDetailsToArray()
        fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchTrainingDetails(), managedObjectContext: moc!, sectionNameKeyPath: nil, cacheName: nil)
        fetchedResultsController?.delegate = self
        fetchedResultsController?.performFetch(nil)
        exerciseTableView.reloadData()
    }

    @IBAction func setsStepperAction(sender: UIStepper) {
        println("\(Int(sender.value))")
        setsNumber.text = Int(sender.value).description
    }

    @IBAction func repsStepper(sender: UIStepper) {
        println("\(Int(sender.value))")
        repsNumber.text = Int(sender.value).description
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return fetchedResultsController?.sections?.count ?? 0
    }

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

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("exerciseCell", forIndexPath: indexPath) as! UITableViewCell
        let details = fetchedResultsController!.objectAtIndexPath(indexPath) as! TrainingDetails
        cell.textLabel!.text = "\(details.exerciseName)"
        cell.detailTextLabel!.text = "Sets: #\(details.setsNumber) Reps: #\(details.repsNumber)"

        return cell
    }

    func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        if self.fetchedResultsController == nil {
            return false
        } else {
            return true
        }
    }

    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        println("section and row \(indexPath.section) \(indexPath.row) ")
        if self.fetchedResultsController == nil {
            println("error when trying to delete object from managed object")

        } else if (editingStyle == UITableViewCellEditingStyle.Delete) {

            switch editingStyle {
            case .Delete:
                moc?.deleteObject(fetchedResultsController?.objectAtIndexPath(indexPath) as! TrainingDetails)
                moc?.save(nil)
            case .Insert:
                break
            case .None:
                break
            }
        }
    }

    //PICKER VIEW DELEGATE AND DATASOURCE METHODS
    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return daysArray.count
    }

    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
            let trainingDay = daysArray[row]
            return trainingDay.day
    }

    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

        let currentDay = daysArray[row]

        let fetchRequest = NSFetchRequest(entityName: "TrainingDetails")
        let predicate = NSPredicate(format: "trainingDay.day == %@", currentDay)
        fetchRequest.predicate = predicate
        let sort = NSSortDescriptor(key: "exerciseName", ascending: true)
        fetchRequest.sortDescriptors = [sort]
        detailsArray = (moc!.executeFetchRequest(fetchRequest, error: nil) as? [TrainingDetails])!
        exerciseTableView.reloadData()
    }

    // MARK: NSFetchedResultsControllerDelegate
    func controllerWillChangeContent(controller: NSFetchedResultsController) {
        self.exerciseTableView.beginUpdates()
    }
    func controller(controller: NSFetchedResultsController,
        didChangeObject anObject: AnyObject,
        atIndexPath indexPath: NSIndexPath?,
        forChangeType type: NSFetchedResultsChangeType,
        newIndexPath: NSIndexPath?)
    {
        switch type {
        case NSFetchedResultsChangeType.Insert:
            // Note that for Insert, we insert a row at the __newIndexPath__
            if let insertIndexPath = newIndexPath {
                self.exerciseTableView.insertRowsAtIndexPaths([insertIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            }
        case NSFetchedResultsChangeType.Delete:
            // Note that for Delete, we delete the row at __indexPath__
            if let deleteIndexPath = indexPath {
                self.exerciseTableView.deleteRowsAtIndexPaths([deleteIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            }
        case NSFetchedResultsChangeType.Update:
            // Note that for Update, we update the row at __indexPath__
            if let updateIndexPath = indexPath {
                let cell = self.exerciseTableView.cellForRowAtIndexPath(updateIndexPath)
                let details = self.fetchedResultsController!.objectAtIndexPath(updateIndexPath) as? TrainingDetails

                cell!.textLabel!.text = "\(details!.exerciseName)"
                cell!.detailTextLabel!.text = "Sets: #\(details!.setsNumber) Reps: #\(details!.repsNumber)"
            }
        case NSFetchedResultsChangeType.Move:
            // Note that for Move, we delete the row at __indexPath__
            if let deleteIndexPath = indexPath {
                self.exerciseTableView.deleteRowsAtIndexPaths([deleteIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            }

            // Note that for Move, we insert a row at the __newIndexPath__
            if let insertIndexPath = newIndexPath {
                self.exerciseTableView.insertRowsAtIndexPaths([insertIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            }
        }    }

    func controller(controller: NSFetchedResultsController,
        didChangeSection sectionInfo: NSFetchedResultsSectionInfo,
        atIndex sectionIndex: Int,
        forChangeType type: NSFetchedResultsChangeType)
    {
        switch type {
        case .Insert:
            let sectionIndexSet = NSIndexSet(index: sectionIndex)
            self.exerciseTableView.insertSections(sectionIndexSet, withRowAnimation: UITableViewRowAnimation.Fade)
        case .Delete:
            let sectionIndexSet = NSIndexSet(index: sectionIndex)
            self.exerciseTableView.deleteSections(sectionIndexSet, withRowAnimation: UITableViewRowAnimation.Fade)
        default:
            ""
        }
    }
    func controllerDidChangeContent(controller: NSFetchedResultsController) {
        exerciseTableView.endUpdates()
    }
}

【问题讨论】:

  • 表格视图未重新加载的原因可能有多种。您也可以发布与表格视图相关的代码吗? detailsArray 是否还包含一些对象?还是空的?
  • 我用完整的代码更新了问题! detailsArray 应该有 TrainingDetails 的对象。
  • 我想你已经弄清楚了问题所在。您的表实际上是从 fetchRequestController 加载其内容,而不是从 details 数组。这就是为什么您的表没有重新加载与给定日期有关的详细信息。

标签: swift uitableview core-data uipickerview nsfetchedresultscontroller


【解决方案1】:

因此,您需要更改与 fetchedResultsController 关联的获取请求,并在其上调用 performFetch(),然后重新加载表视图。在你的

 func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
  let currentDay = daysArray[row]
        //Update the fetch request related to the fetchedResultsController.fetchRequest that table view controller uses for its data
        let fetchRequest = fetchedResultsController.fetchRequest
        let predicate = NSPredicate(format: "trainingDay.day == %@", currentDay)
        fetchRequest.predicate = predicate
        let sort = NSSortDescriptor(key: "exerciseName", ascending: true)
        fetchRequest.sortDescriptors = [sort]
        //Perform fetch afresh
        fetchedResultsController.performFetch(nil);

        //Now reload the table view
        exerciseTableView.reloadData()
}

参考:Documentation

修改获取请求 您不能简单地更改获取请求 修改结果。如果你想改变获取请求,你 必须:

如果您正在使用缓存,请将其删除(使用 deleteCacheWithName:)。

如果要更改 fetch,通常不应使用缓存 请求。

更改获取请求。

调用 performFetch:.

【讨论】:

  • 嘿!感谢您的回答!使用您提供的代码,假设我为“星期一”添加了我想要的所有内容,现在我为“星期二”选择另一行,表格视图重新加载但变空,如果我再次选择“星期一”,它仍然是空的,它确实不要重新加载我之前添加的内容。
  • 我在想:如果我们在选择器视图中获取选定的行,提取它的名称并将其分配给 var : string 并使用它而不是 让 currentDay = daysArray[row] ?我想问题就在那里,currentDay 没有收到正确的 CoreData 日期,因为 daysArrow 只是在此表视图中正确排序事物的工具,保存的内容实际上并未保存在该数组中。如果我错了,请纠正我!
  • 如果从选择器视图中获取字符串是解决方案,你能教我怎么做吗?
  • 我成功了!我从 pickerView 中获取了字符串并用于将正确的日期分配给 currentDay,现在每当我在选择器视图中选择不同的行时,它都会以正确的方式重新加载!
猜你喜欢
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-08
相关资源
最近更新 更多