Xcode表视图节未更新

时间:2019-02-11 17:54:14

标签: swift xcode tableview sections

我创建了一个新的Xcode 9.4.1 Master-Detail项目。我已经以编程方式实现了自定义单元,并且所有工作都按预期进行。我的应用程序是Ham Radio转发器的数据库。我正在创建用于练习的应用程序。我现在正在尝试实现按状态对转发器条目进行分组的部分。我的添加/删除功能可以从TableView页面正常工作。从适当的部分添加/删除条目。我已将其设置为在详细信息视图中执行转发器条目更新。问题是,当我在详细视图中更改状态然后返回到主视图时,表视图不会更改条目分组。我已经在WillAppear函数下实现了self.tableView.reloadData()

这是我的MasterViewController的代码:

import UIKit
import CoreData

class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate{

    let cellTableIdentifier = "Cell"

    var detailViewController: DetailViewController? = nil
    var managedObjectContext: NSManagedObjectContext? = nil

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(CustomCell.self,forCellReuseIdentifier: cellTableIdentifier)

        // Do any additional setup after loading the view, typically from a nib.
        navigationItem.leftBarButtonItem = editButtonItem

        let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:)))
        navigationItem.rightBarButtonItem = addButton
        if let split = splitViewController {
            let controllers = split.viewControllers
            detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        clearsSelectionOnViewWillAppear = splitViewController!.isCollapsed
        super.viewWillAppear(animated)
        // reload the data into the TableView
        self.tableView.reloadData()
        //self.tableView.reloadSections([1,2,3], with: .none )
    }

    // Adds Repeaters to Table View, saves in Core Data
    @objc
    func insertNewObject(_ sender: Any)
    {
        // create an Alert with a textFields
        let alertController = UIAlertController(title: "Add Repeater",
                                                message: "",
                                                preferredStyle: UIAlertControllerStyle.alert)

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="State"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="County"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="City"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="Call Sign"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="Input Frequency"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="Output Frequency"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="Uplink Tone"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="Downlink Tone"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="Offset"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // add the textField to the Alert. Create a closure to handle the configuration
        alertController.addTextField(configurationHandler: {(textField: UITextField!) in
            textField.placeholder="Use"
            textField.keyboardType=UIKeyboardType.emailAddress
        })

        // create a default action for the Alert
        let defaultAction = UIAlertAction(
            title: "Create",
            style: UIAlertActionStyle.default,
            handler: {(alertAction: UIAlertAction!) in
                // get the input from the alert controller
                let context = self.fetchedResultsController.managedObjectContext
                let newRepeater = Repeaters(context: context)

                newRepeater.state = (alertController.textFields![0]).text!
                newRepeater.county = (alertController.textFields![1]).text!
                newRepeater.location = (alertController.textFields![2]).text!
                newRepeater.call = (alertController.textFields![3]).text!
                newRepeater.input_Freq = (alertController.textFields![4]).text!
                newRepeater.output_Freq = (alertController.textFields![5]).text!
                newRepeater.uplink_Tone = (alertController.textFields![6]).text!
                newRepeater.downlink_Tone = (alertController.textFields![7]).text!
                newRepeater.offset = (alertController.textFields![8]).text!
                newRepeater.use = (alertController.textFields![9]).text!

                // Save the context.
                do {
                    try context.save()
                } catch {
                    let nserror = error as NSError
                    fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                }

                // reload the data into the TableView
                self.tableView.reloadData()
        })
        // cancel button
        let cancelAction = UIAlertAction(
            title: "Cancel",
            style: UIAlertActionStyle.cancel,
            handler:nil)

        // add the actions to the Alert
        alertController.addAction(defaultAction)
        alertController.addAction(cancelAction)

        // generate test data
        gernerateTestData(alertController: alertController)

        // display the Alert
        present(alertController, animated: true, completion: nil)
    }

    // Creates test data in Alert Controller
    func gernerateTestData(alertController:UIAlertController)
    {
        // increment count
        //count += 1
        // get the textfields and assign test data
        (alertController.textFields![0]).text = "Ohio"
        (alertController.textFields![1]).text = "Lake"
        (alertController.textFields![2]).text = "Mentor"
        (alertController.textFields![3]).text = "N8BC"
        (alertController.textFields![4]).text = "147.165"
        (alertController.textFields![5]).text = "147.765"
        (alertController.textFields![6]).text = "110.9"
        (alertController.textFields![7]).text = "110.9"
        (alertController.textFields![8]).text = "+"
        (alertController.textFields![9]).text = "OPEN"
    }


    // MARK: - Segues

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDetail" {
            if let indexPath = tableView.indexPathForSelectedRow {
            let object = fetchedResultsController.object(at: indexPath)
                let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
                controller.detailItem = object
                controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
                controller.navigationItem.leftItemsSupplementBackButton = true
            }
        }
    }

    // MARK: - Table View

    override func numberOfSections(in tableView: UITableView) -> Int {
        return fetchedResultsController.sections?.count ?? 0
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        //return "Section \(section)"
        //return "Ohio"
        if let sections = fetchedResultsController.sections {
            let currentSection = sections[section]
            return String(currentSection.name)
        }
        return nil
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let sectionInfo = fetchedResultsController.sections![section]
        return sectionInfo.numberOfObjects
    }

    // *** Save, allows you to revert to standard cell
//    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//        let repeater = fetchedResultsController.object(at: indexPath)
//        //configureCell(cell, withEvent: event)
//        configureCell(cell, withEvent: repeater)
//        return cell
//    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellTableIdentifier, for: indexPath) as! CustomCell
        let repeater = fetchedResultsController.object(at: indexPath)
        cell.call = repeater.call!
        //cell.state = repeater.state!
        cell.city = repeater.location!
        return cell
    }

    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            let context = fetchedResultsController.managedObjectContext
            context.delete(fetchedResultsController.object(at: indexPath))

            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.performSegue(withIdentifier: "showDetail", sender:tableView)
    }

    func configureCell(_ cell: UITableViewCell, withEvent repeater: Repeaters) {
                cell.textLabel!.text = repeater.call!.description
    }

    // MARK: - Fetched results controller

    var fetchedResultsController: NSFetchedResultsController<Repeaters> {
    if _fetchedResultsController != nil {
        return _fetchedResultsController!
    }
        let fetchRequest: NSFetchRequest<Repeaters> = Repeaters.fetchRequest()

        // Set the batch size to a suitable number.
        fetchRequest.fetchBatchSize = 20

        // Edit the sort key as appropriate.
        let sortDescriptor = NSSortDescriptor(key: "call", ascending: false)

        fetchRequest.sortDescriptors = [sortDescriptor]

        // Edit the section name key path and cache name if appropriate.
        // nil for section name key path means "no sections".
        let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: "state", cacheName: "Master")
        aFetchedResultsController.delegate = self
        _fetchedResultsController = aFetchedResultsController

        do {
            try _fetchedResultsController!.performFetch()
        } catch {
             // Replace this implementation with code to handle the error appropriately.
             // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
             let nserror = error as NSError
             fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }

        return _fetchedResultsController!
    }    
    var _fetchedResultsController: NSFetchedResultsController<Repeaters>? = nil

    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        tableView.beginUpdates()
    }

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
        switch type {
            case .insert:
                tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
            case .delete:
                tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
            default:
                return
        }
    }

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
            case .insert:
                tableView.insertRows(at: [newIndexPath!], with: .fade)
            case .delete:
                tableView.deleteRows(at: [indexPath!], with: .fade)
            case .update:
                //configureCell(tableView.cellForRow(at: indexPath!)!, withEvent: anObject as! Repeaters)
                print()
            case .move:
                //configureCell(tableView.cellForRow(at: indexPath!)!, withEvent: anObject as! Repeaters)
                //tableView.moveRow(at: indexPath!, to: newIndexPath!)
                print()
        }
    }

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        tableView.endUpdates()
    }

    /*
     // Implementing the above methods to update the table view in response to individual changes may have performance implications if a large number of changes are made simultaneously. If this proves to be an issue, you can instead just implement controllerDidChangeContent: which notifies the delegate that all section and object changes have been processed.

     func controllerDidChangeContent(controller: NSFetchedResultsController) {
         // In the simplest, most efficient, case, reload the table view.
         tableView.reloadData()
     }
     */
}

1 个答案:

答案 0 :(得分:0)

您可以尝试通过向单元格中添加适当的委托来重新加载表,例如

protocol DetailsCellDelegate: class {
    func updateTable(with: Data)
}

并通过调用delegate?.updateTable(with: data)

对您的数据执行此委托