我创建了一个新的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()
}
*/
}
答案 0 :(得分:0)
您可以尝试通过向单元格中添加适当的委托来重新加载表,例如
protocol DetailsCellDelegate: class {
func updateTable(with: Data)
}
并通过调用delegate?.updateTable(with: data)