[英]How do I use NSFetchedResultsControllerDelegate in multiple ViewController without repeating the controller code?
I am making an app that uses Core Data, it happens that in this app I have three tableViews populated with different data and all of them are in different controllers, to avoid repeating the code (since it is exactly the same) I would like to have a solution for this. 我正在制作一个使用Core Data的应用程序,碰巧在这个应用程序中,我有三个用不同数据填充的tableView,并且它们都在不同的控制器中,以避免重复代码(因为它完全相同),我想有一个解决方案。
I have tried through protocols and with a MainController that inherits from UIViewController, which in turn had the extension of NSFetchedResultsControllerDelegate. 我已经尝试过协议,并且使用了从UIViewController继承的MainController,后者又扩展了NSFetchedResultsControllerDelegate。 Im almost positive that doing a super class where I can put this code is the solution, but since I'm new to swift and to programming and I'm also positive that there is something that im not doing as it was supposed.
我几乎肯定地说,可以在其中放置此代码的超类是解决方案,但是由于我是快速入门和编程的新手,所以我也很肯定有些即时消息没有按照预期执行。
In the parent class I've made something like this: 在父类中,我做了这样的事情:
class MainController: UIViewController, NSFetchedResultsController {
var activeTableView: UITableView?
}
And in the child: 而在孩子中:
class SecdController: MainController {
@IBOutlet weak var tableView: UITableView!
override var activeTableView: UITableView? {
get {return tableView}
set {}
}
}
Below is the code I want to be called three controllers. 下面是我要称为三个控制器的代码。
extension SomeController: NSFetchedResultsControllerDelegate {
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: .top)
break
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
break
case .update:
tableView.reloadRows(at: [indexPath!], with: .top)
case .move:
tableView.reloadRows(at: [indexPath!], with: .top)
default:
fatalError("feature not yet implemented")
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
let indexSet = IndexSet(integer: sectionIndex)
switch type {
case .insert:
tableView.insertSections(indexSet, with: .top)
case .delete:
tableView.deleteSections(indexSet, with: .top)
case .update, .move:
fatalError("Invalid change.")
default:
fatalError("feature not yet implemented")
}
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
}
Thanks in advance :) 提前致谢 :)
Your MainController
should handle NSFetchedResultsControllerDelegate
instead of inherit NSFetchedResultsController
您的
MainController
应该处理NSFetchedResultsControllerDelegate
而不是继承NSFetchedResultsController
class MainController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var fetchedResultsController: NSFetchedResultsController<NSManagedObject>?
override func viewDidLoad() {
super.viewDidLoad()
setupFetchedResultsController()
fetchedResultsController?.delegate = self
// perform fetch
}
func setupFetchedResultsController() {
preconditionFailure("The method must be overridden and initialize the fetch result controller.")
}
}
extension MainController: NSFetchedResultsControllerDelegate {
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
// Do not force unwrap
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .top)
break
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
break
case .update:
tableView.reloadRows(at: [indexPath!], with: .top)
case .move:
tableView.reloadRows(at: [indexPath!], with: .top)
default:
fatalError("feature not yet implemented")
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
let indexSet = IndexSet(integer: sectionIndex)
switch type {
case .insert:
tableView.insertSections(indexSet, with: .top)
case .delete:
tableView.deleteSections(indexSet, with: .top)
case .update, .move:
fatalError("Invalid change.")
default:
fatalError("feature not yet implemented")
}
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
}
And then in the other view controller just override setupFetchedResultsController()
and setup the fetch results controller: 然后在另一个视图控制器中,只需重写
setupFetchedResultsController()
并设置获取结果控制器:
class SecondController: MainController {
override func createFetchResultController() {
let fetchRequest: NSFetchRequest<...> = ...
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
fetchedResultsController = ...
}
}
This is a tricky one because the normal solutions of refactoring the delegates to its own class don't work because the class needs to handle both the table delegate (ie be a UITableViewController) and also be a fetch controller delegate. 这是一个棘手的问题,因为将委托重构为其自己的类的常规解决方案不起作用,因为该类既需要处理表委托(即,是UITableViewController),又需要处理获取控制器委托。 Thankfully there is a simple solution which is to use a technique called composition.
值得庆幸的是,有一个简单的解决方案是使用一种称为合成的技术。 Put the duplicated table and fetch in a
UITableViewController
subclass that implements NSFetchedResultsControllerDelegate
and make a fetchedResultsController
property (pictured on right in image below). 把复制表,并在获取
UITableViewController
实现子类NSFetchedResultsControllerDelegate
并作出fetchedResultsController
属性(在下面的图像描绘上右图)。
For the code that is different put that in several UIViewController
subclasses (pictured on left in image below) for each specific case. 对于不同的代码,针对每种特定情况,将其放在几个
UIViewController
子类中(如左图所示)。
Use an embed segue to make this view controller contain the table controller. 使用embed segue使该视图控制器包含表控制器。 In the
viewDidLoad
create the fetch controller and set it to the table controller. 在
viewDidLoad
创建访viewDidLoad
控制器并将其设置为表控制器。 eg 例如
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:@"embed"]){
self.fetchedTableViewController = segue.destinationViewController;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
self.fetchedTableViewController.fetchedResultsController = self.fetchedResultsController;
// optional for more customization
self.fetchedTableViewController.tableView.delegate = self;
self.fetchedTableViewController.tableView.dataSource = self;
}
If you want to handle some specific table or fetch delegate methods then a nifty way is to set the view controller as the delegates, and then forward any of the method calls on to the embedded table controller. 如果要处理某些特定的表或获取委托方法,则一种不错的方法是将视图控制器设置为委托,然后将任何方法调用转发到嵌入式表控制器。 eg
例如
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.fetchedTableViewController controllerDidChangeContent:controller];
In that case you should also implement the forwardingTargetForSelector
pattern to make sure everything else is forwarded on too. 在这种情况下,您还应该实现
forwardingTargetForSelector
模式,以确保其他所有内容也都被转发。
- (id)forwardingTargetForSelector:(SEL)aSelector{
if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDelegate), aSelector)){
if([self.fetchedTableViewController respondsToSelector:aSelector]){
return self.fetchedTableViewController;
}
}
else if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDataSource), aSelector)){
if([self.fetchedTableViewController respondsToSelector:aSelector]){
return self.fetchedTableViewController;
}
}
else if(MHFProtocolHasInstanceMethod(@protocol(NSFetchedResultsControllerDelegate), aSelector)){
if([self.fetchedTableViewController respondsToSelector:aSelector]){
return self.fetchedTableViewController;
}
}
else if(MHFProtocolHasInstanceMethod(@protocol(UIDataSourceModelAssociation), aSelector)){
if([self.fetchedTableViewController respondsToSelector:aSelector]){
return self.fetchedTableViewController;
}
}
return [super forwardingTargetForSelector:aSelector];
}
- (BOOL)respondsToSelector:(SEL)aSelector{
if([super respondsToSelector:aSelector]){
return YES;
}
else if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDelegate), aSelector)){
if([self.fetchedTableViewController respondsToSelector:aSelector]){
return YES;
}
}
else if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDataSource), aSelector)){
if([self.fetchedTableViewController respondsToSelector:aSelector]){
return YES;
}
}
else if(MHFProtocolHasInstanceMethod(@protocol(NSFetchedResultsControllerDelegate), aSelector)){
if([self.fetchedTableViewController respondsToSelector:aSelector]){
return YES;
}
}
else if(MHFProtocolHasInstanceMethod(@protocol(UIDataSourceModelAssociation), aSelector)){
if([self.fetchedTableViewController respondsToSelector:aSelector]){
return YES;
}
}
return NO;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.