0

I have a View Controller, called ScorecardViewController, that contains a UITableView, called HolesTable, which is correctly populated by a FetchedResultsController.

However, when the user edits any data, none of the FRC delegate methods are called - i.e. I've set breakpoints on each FRC delegate method and none are triggered.

ScorecardViewController is the delegate for HolesTable and implements the necessary set of methods for it to work. Also, HolesTable, has it's data source and delegate set in IB to be ScorecardViewController.

For context, elsewhere in the app, I have a near-identical setup that is working correctly. I have a View Controller, CourseViewController, which hosts a UITableView, ScorecardTable, that has an FRC linked to it.

ScorecardTable populates correctly from the FRC and all FRC delegate methods are firing as expected.

After extensive review of my code and researching online, I'm concluding that I have missed a step somewhere that connects HoleTable to the FRC delegate, but I can't work out where this happening as my inspection of the two VC's doesn't show anything obvious.

Is there anything else I might be missing out on here? And what code can I post that would help to identify where the problem is?

Thanks!

-- UPDATE 1

The FRC is defined thus:

fileprivate lazy var fetchedResultsController: NSFetchedResultsController<Hole> = {
// Create Fetch Request
let fetchRequest: NSFetchRequest<Hole> = Hole.fetchRequest()

// Configure Fetch Request
self.teeColourString = self.scorecard?.value(forKey: "teeColour") as! String?
fetchRequest.predicate = NSPredicate(format: "%K == %@ AND %K == %@", "appearsOn.offeredAt.name", self.courseName!, "appearsOn.teeColour", self.teeColourString!)

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

// Create Fetched Results Controller
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.coreDataManager.mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

// Configure Fetched Results Controller
fetchedResultsController.delegate = self

return fetchedResultsController

}()

The FRC works well and it populates the connected tableView object, HoleTable.

The Hole table contains three integer columns HoleNum, Par and StrokeIndex. I have a custom cell, HoleTableViewCell where these values are displayed inside HoleTable.

Par and StrokeIndex can be updated through an instance of HoleTable with the user editing the cell directly. The code for `HoleTableViewCell' is:

class HoleTableViewCell: UITableViewCell, UITextFieldDelegate {

    @IBOutlet weak var holeNumLabel: UILabel!
    @IBOutlet weak var SIField: UITextField!
    @IBOutlet weak var parField: UITextField!

    static let reuseIdentifier = "HoleTableViewCell"

    func textFieldDidBeginEditing(_ textField: UITextField) {
        print("Editing started")
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        if textField.tag == 4 {
            //ParField has been edited
            print("Par is now " + textField.text!)
        } else if textField.tag == 5 {
            // SIField has been edited
            print("SI is now " + textField.text!)
        }
    }
    override func awakeFromNib() {
        super.awakeFromNib()

        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
        SIField.delegate = self
        SIField.tag = 4
        parField.delegate = self
        parField.tag = 5
    }
}

At run-time, edits to the text fields SIField and parField trigger textFieldDidBeginEditing and textFieldDidEndEditing as I would expect.

What does not happen is the triggering of the FRC delegate methods. These are defined in the class for the UITableView, ScorecardViewController where the FetchedResultsControllerDelegate protocol methods are set up.

-- UPDATE 2

After further investigation, I think the reason the FRC delegate methods are not firing is because there is no update happening to the Managed Object Context behind the FRC.

I'm going to look into this further to see if there's a straightforward way to make this happen.

Dave
  • 71
  • 10

1 Answers1

0

Turns out the solution to this was straightforward, but took a few brain cells to figure out.

The missing piece was that I needed to pass a reference to the object from the HolesTable TableView to the `HoleTableViewCell' cell so my edits within the cell method triggered the FRC delegate methods.

The new class 'HoleTableViewCell' definition looks like this:

import UIKit
import CoreData

class HoleTableViewCell: UITableViewCell, UITextFieldDelegate {

    @IBOutlet weak var holeNumLabel: UILabel!
    @IBOutlet weak var SIField: UITextField!
    @IBOutlet weak var parField: UITextField!

    var hole: Hole?

    static let reuseIdentifier = "HoleTableViewCell"

    func textFieldDidBeginEditing(_ textField: UITextField) {
        print("Editing started")
    }

    // This will need beefing up to enforce rules for Par and SI
    func textFieldDidEndEditing(_ textField: UITextField) {
        if textField.tag == 4 || textField.tag == 5 {
            //ParField has been edited

            //Prepare the Hole record for sending back to calling controller
            hole?.setValue(Int(parField.text!), forKeyPath: "par")
            hole?.setValue(Int(SIField.text!), forKey: "strokeIndex")
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
        SIField.delegate = self
        SIField.tag = 4
        parField.delegate = self
        parField.tag = 5
    }
}

And, in the class definition for the UITableView which holds the cell, the following is needed:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

guard let cell = tableView.dequeueReusableCell(withIdentifier: HoleTableViewCell.reuseIdentifier, for: indexPath) as? HoleTableViewCell else {
    fatalError("Unexpected Index Path")
}

// Fetch Holes
let hole = fetchedResultsController.object(at: indexPath)


// Pass the hole to the cell instance so edits in situ will trigger FRC delegate methods
cell.hole = hole

return cell

}

Dave
  • 71
  • 10