NSFetchedResultsController распознает «удалить», когда это должно быть «обновление» - PullRequest
0 голосов
/ 13 октября 2018

После инициализации и заполнения FRC появляется обновление (по-видимому) независимой переменной, чтобы изменить ожидаемое поведение FRC.

Я создаю приложение, связанное с гольфом, и FRC определяется впредставление о том, что Scorecard объекты управляются как:

fileprivate lazy var fetchedResultsController: NSFetchedResultsController<Hole> = {

    let fetchRequest: NSFetchRequest<Hole> = Hole.fetchRequest()

    self.teeColourString = self.scorecard?.value(forKey: "teeColour") as! String?

    fetchRequest.predicate = NSPredicate(format: "%K == %@ AND %K == %@", "appearsOn.offeredAt", (self.course)!, "appearsOn.teeColour", self.teeColourString!)

    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "holeNumber", ascending: true)]

    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataManager.mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

    // Configure Fetched Results Controller
    fetchedResultsController.delegate = self

    return fetchedResultsController
}()

Базовая модель данных требует, чтобы для системы показателей (Scorecard) было ровно 18 лунок (Hole объектов), и что система показателей может 'не может быть создано без них.Каждое поле для гольфа может иметь несколько карт оценок в зависимости от цвета футболки.Для каждого Scorecard его набор из 18 Hole записей привязан к teeColour и Course, для которых Scorecard предназначен (обозначен appearsOn).

Во время выполнения на экране редактора счетов отображается цвет тройника и таблица связанных Hole записей.

Scorecard Editor

.Цвет тройника не изменился, функциональность работает должным образом.

Однако, если цвет тройника изменяется, FRC идентифицирует любое последующее редактирование любой записи Hole, не рассматриваемой как update, но какdelete:

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {

    switch type {
    case .update:
        holesTable.reloadRows(at: [indexPath!], with: .automatic)
        lookForSIProblems(holes: fetchedResultsController.fetchedObjects!, saveMode: false)
        saveButton.isEnabled = true
    case .insert:
        holesTable.insertRows(at: [newIndexPath!], with: .automatic)
    case .delete:
        break
    case .move:
        holesTable.moveRow(at: indexPath! as IndexPath, to: newIndexPath! as IndexPath)
    }
}

И окно терминала XCode сообщает:

[error] fault: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (17) must be equal to the number of rows contained in that section before the update (18), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)

Обновление цвета тройника достигается нажатием на UIButton«Тройник цвет» на экране.Это запускает всплывающее окно прокрутки, из которого пользователь может выбрать новый цвет тройника.Результирующий выбор затем обновляет цвет фона UILabel рядом с кнопкой, чтобы показать текущий цвет тройника.

UIButton для выбора цвета тройника имеет следующий код IBAction:

@IBAction func showPopUpColourPicker(_ sender: UIButton) {
    // User is choosing the tee Colour for the scorecard
    let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbPopUpID") as! PopUpViewController

    popOverVC.modalPresentationStyle = .popover

    popOverVC.popoverPresentationController?.sourceView = sender
    popOverVC.popoverPresentationController?.sourceRect = sender.bounds

    popOverVC.popoverPresentationController!.delegate = self

    popOverVC.completionHandler = {(chosenTeeColour : String?) in
        if let valueSelected = chosenTeeColour
        {
            self.saveButton.isEnabled = true
            self.teeColourString = valueSelected
            self.scorecard?.setValue(valueSelected, forKey: "teeColour") // Make this the default for all new scorecards
            self.teeColourString = (self.scorecard?.value(forKey: "teeColour") as! String)

            self.teeColour.setup(teeColour: self.teeColourString!)
        }
    }

    popOverVC.preferredContentSize = CGSize(width: 320, height: 100)

    present(popOverVC, animated: true, completion: nil)

}

В свою очередь, класс PopUpViewController определяется как:

class PopUpViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {

@IBOutlet weak var teeBoxPicker: UIPickerView!

var completionHandler : ((String?)->(Void))?
var chosenTeeColour: String?
var pickerData: [String] = [String]()


override func viewDidLoad() {
    super.viewDidLoad()

    self.view.backgroundColor = UIColor.black.withAlphaComponent(0.8)

    // Connect data:
    self.teeBoxPicker.delegate = self
    self.teeBoxPicker.dataSource = self

    pickerData = ["Red", "Blue", "Yellow", "White", "Green", "Black"]

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

// The number of columns of data
func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1
}

// The number of rows of data
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return pickerData.count
}

// The data to return for the row and component (column) that's being passed in
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return pickerData[row]
}

// Retrieve the selected value and force lowercase for insertion into database
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

    let valueSelected = pickerData[row] as String

    chosenTeeColour = valueSelected.lowercased()

    self.dismiss(animated: true, completion: {[weak self] in
        if let handler = self?.completionHandler
        {
            handler(self?.chosenTeeColour)
        }
    })


    self.view.removeFromSuperview()
}

func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {

    var labelBackgroundColour: UIColor
    var labelTextColor: UIColor

    let teeColour = pickerData[row]
    let pickerLabel = UILabel()

    labelBackgroundColour = getTeeColour(teeDescriptor: teeColour.lowercased())

    if labelBackgroundColour == .white || labelBackgroundColour == .yellow {
        labelTextColor = UIColor.black
    } else {
        labelTextColor = UIColor.white
    }

    pickerLabel.backgroundColor = labelBackgroundColour
    pickerLabel.textColor = labelTextColor

    let myTitle = NSAttributedString(string: teeColour, attributes: [NSAttributedStringKey.foregroundColor:labelTextColor])
    pickerLabel.attributedText = myTitle
    pickerLabel.textAlignment = .center

    return pickerLabel
  }
}

Я не могу определить, как обновление цвета тройника должно изменить поведение FRC или его UITableView каккажется, что нет никакой связи между ними.

Что здесь происходит?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...