0

Посмотрите этот код:CoreData - PickerView Обновление Tableview

Модели:

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] Я должен приписать fetchedResultsController из CoreData в currentDay, а затем попытаться обновить tableView.

Мой вопрос: правильно ли я это считаю? Как мне это сделать?

Я новичок в Swift, мне бы понравились некоторые примеры того, как это сделать.

Спасибо заранее!

UPDATE -> Полный код

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() 
    } 
} 
+1

Может быть несколько причин, по которым табличный вид не перезагружается. Можете ли вы опубликовать свой код, связанный с таблицей? Кроме того, detailsArray содержит некоторые объекты? или он пуст? – Shripada

+0

Я обновил вопрос с полным кодом! detailsArray должен иметь объекты TrainingDetails. –

+0

Я думаю, вы уже поняли, в чем проблема. Вы фактически загружаете его содержимое из fetchRequestController, а не в массив деталей. Вот почему ваша таблица не перезагружает детали, относящиеся к данному дню. – Shripada

ответ

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

Модификация Fetch Запрос Вы не можете просто изменить выборку запроса для изменения результатов. Если вы хотите изменить запрос на выборку, вы должны: :

Если вы используете кеш, удалите его (используя deleteCacheWithName :).

Как правило, вы не должны использовать кеш, если вы меняете запрос на выборку .

Измените запрос на выборку.

Invoke performFetch :.

+0

Эй! Спасибо за Ваш ответ!С кодом, который вы указали, допустим, я добавлю все, что хочу для «Понедельника», и теперь я выбираю еще одну строку для «Вторника», просмотр таблицы перезагружается, но становится пустым, если я снова выбираю «Понедельник», он остается пустым, он делает не перезагружайте предыдущий материал, который я добавил. –

+0

Я подумал: что, если мы получим выбранную строку в представлении выбора, извлеките ее имя и назначьте ее в строку ** var: string ** и используйте ее вместо ** let currentDay = daysArray [row] **? Я думаю, проблема в том, что currentDay не получает надлежащий день CoreData, потому что ** daysArrow ** - это просто инструмент для правильного упорядочивания данных в этом представлении таблицы, сохраненные вещи фактически не сохраняются в этом массиве. Поправьте меня если я ошибаюсь! –

+0

Если получение строки из представления выбора является решением, не могли бы вы научить меня, как это сделать? –

Смежные вопросы