Paul S.
Paul S.

Reputation: 1352

Issues with UITableViewController with Segues, Core Data and Swift

Xcode 6.0.1, Swift iOS 8

I have what I think is a pretty trvial setup, but I am missing something that is causing issues, or is the default behaviour.

I have the following:

Tab Bar Controller -> Navigation Controller -> Table View Controller -Seque-> Table View Controller

enter image description here

I have the UIBarButtonItem 'Add' button (addPlayerInformationDetail) wired to the 2nd Table View Controller. The problem is when I push the controller via the segue, code runs on the wrong Table View Controller, and it crashes. I understand why it is crashing, but I don't understand why it's doing something on the 1st view controller. The 1st Table View Controller is also the NSFetchedResultsControllerDelegate.

The first Table View Controller (PlayerInformationTableViewController ) is using the standard Table View Controller boiler code. Here is the Segue calling the

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if debug==1 {
        println("Running: ", reflect(self).summary.pathExtension,__FUNCTION__)
    }

    if segue.identifier == "addPlayerInformationDetail" {

       //Nothing to do at the moment

    } else if segue.identifier == "editPlayerInformationDetail" {

        var indexPath:NSIndexPath = tableView.indexPathForSelectedRow()!
        var vc                    = segue.destinationViewController as PlayerInformationDetailTableViewController
        vc.managedObjectID        = self.fetchedResultsController.objectAtIndexPath(indexPath).objectID
    }
}

Here is the trace of all the methods and I pointed out where the code is going back to the 1st Table View Controller:

(Running: , AppDelegate, managedObjectContext)
(Running: , AppDelegate, persistentStoreCoordinator)
(Running: , AppDelegate, managedObjectModel)
(Running: , AppDelegate, applicationDocumentsDirectory)
(Running: , AppDelegate, application(_:didFinishLaunchingWithOptions:))
(Running: , PlayerInformationTableViewController, viewDidLoad())
(Running: , PlayerInformationTableViewController, viewWillAppear)
(Running: , PlayerInformationTableViewController, numberOfSectionsInTableView)
(Running: , PlayerInformationTableViewController, fetchedResultsController)
(Running: , PlayerInformationTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationTableViewController, fetchedResultsController)
(Running: , PlayerInformationTableViewController, numberOfSectionsInTableView)
(Running: , PlayerInformationTableViewController, fetchedResultsController)
(Running: , PlayerInformationTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationTableViewController, fetchedResultsController)
(Running: , AppDelegate, applicationDidBecomeActive)
(Running: , PlayerInformationTableViewController, prepareForSegue(_:sender:))
(Running: , PlayerInformationDetailTableViewController, putABorderAroundButtons())
(Running: , PlayerInformationDetailTableViewController, viewWillAppear)
(Running: , PlayerInformationDetailTableViewController, refreshInterface())
newPlayer (Function)
(Running: , PlayerInformationDetailTableViewController, newPlayer())
(Ending: , PlayerInformationDetailTableViewController, newPlayer())

Why is it going back to PlayerInformationTableViewController???

(Running: , PlayerInformationTableViewController, numberOfSectionsInTableView)
(Running: , PlayerInformationTableViewController, fetchedResultsController)
(Running: , PlayerInformationTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationTableViewController, fetchedResultsController)


(Running: , PlayerInformationDetailTableViewController, numberOfSectionsInTableView)
(Running: , PlayerInformationDetailTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationDetailTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationDetailTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationDetailTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationDetailTableViewController, numberOfSectionsInTableView)
(Running: , PlayerInformationDetailTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationDetailTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationDetailTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationDetailTableViewController, tableView(_:numberOfRowsInSection:))
(Running: , PlayerInformationTableViewController, tableView(_:cellForRowAtIndexPath:))
(Running: , PlayerInformationTableViewController, tableView(_:canEditRowAtIndexPath:))
(Running: , PlayerInformationTableViewController, configureCell(_:atIndexPath:))
(Running: , PlayerInformationTableViewController, fetchedResultsController)

After the Add button is tapped and (Ending: , PlayerInformationDetailTableViewController, newPlayer()) completes why is code in the PlayerInformationTableViewController running? I am adding a row into Core Data, but it shouldn't have anything to do with the NSFetchedResultsControllerDelegate in PlayerInformationTableViewController.

Here is the flow of Code in PlayerInformationDetailTableViewController

override func viewWillAppear(animated: Bool) {

    if debug==1 {
        println("Running: ", reflect(self).summary.pathExtension,__FUNCTION__)
    }

    refreshInterface()
}

func refreshInterface(){
    if debug==1 {
        println("Running: ", reflect(self).summary.pathExtension,__FUNCTION__)
    }

    if managedObjectID != nil {

        println("existingPlayer \(existingPlayer)")
        existingPlayer()
    } else {

        println("newPlayer \(newPlayer)")
        newPlayer()
    }
}

func newPlayer(){
    if debug==1 {
        println("Running: ", reflect(self).summary.pathExtension,__FUNCTION__)
    }

    //insert a new object in Core Data

    var newPlayerInformation = NSEntityDescription.insertNewObjectForEntityForName("PlayerInformation", inManagedObjectContext: managedObjectContext!) as PlayerInformation

    var newFirstName  = playerInformationFirstNameTextField.text
    var newLastName   = playerInformationLastNameTextField.text
    var newBirthPlace = playerInformationBirthPlaceTextField.text

    newPlayerInformation.firstName  = playerInformationFirstNameTextField.text
    newPlayerInformation.lastName   = playerInformationLastNameTextField.text
    newPlayerInformation.birthPlace = playerInformationBirthPlaceTextField.text

    if debug==1 {
        println("Ending: ", reflect(self).summary.pathExtension,__FUNCTION__)
    }
}

I hope I explained this properlly, as it's been really frustrating and I'm sure it's something simple I've missed. If I coment out // newPlayer() in func refreshInterface(), the code nevers goes back to PlayerInformationTableViewController. Thanks in advance. -PaulS.

Upvotes: 0

Views: 285

Answers (1)

zisoft
zisoft

Reputation: 23078

The tracelog shows that your NSFetchedResultsController is detecting a change in its managedObjectContext, due to adding a new record. It immediately updates the related information numberOfRowsInSection...

According to the NSFetchedResultsController Class Reference:

In addition, fetched results controllers provide the following features:

Optionally monitor changes to objects in the associated managed object context, and report changes in the results set to its delegate (see The Controller’s Delegate).

To disable this tracking the NSFetchedResultsController's delegate should be set to nil

Upvotes: 1

Related Questions