После инициализации и заполнения 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](https://i.stack.imgur.com/OXpzJ.png)
.Цвет тройника не изменился, функциональность работает должным образом.
Однако, если цвет тройника изменяется, 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
каккажется, что нет никакой связи между ними.
Что здесь происходит?