【发布时间】:2020-07-13 20:16:34
【问题描述】:
我正在尝试将 MVVM 与 Swift 一起使用。我有一个使用 NSFetchedResultsController 的 UITableViewController,以及一个在 CoreData db 中添加/编辑数据的后台进程。
我不知道在哪里处理 fetchedResultsControllerDelegate 方法。 viewModel 还是 viewController?
因为 UITableView 会在 CoreData 中的数据更新时自动更新,所以在我看来,就像在每个 NSManagedObject 实例周围制作一个包装视图模型对象,并将其绑定到表视图,不是这样做的正确方法。这种方式有点违背了使用 NSFetchedResultsController 的目的。
这是我正在使用的简单 MVC 代码,MVVM 化的最佳方法是什么?
// Data model
@objc(Post)
public class Post: NSManagedObject {
@NSManaged public var userName: String?
@NSManaged public var createdAt: Date?
@nonobjc public class func fetchRequest() -> NSFetchRequest<Post> {
return NSFetchRequest<Post>(entityName: "Post")
}
}
// View controller
class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate {
var fetchedResultsController: NSFetchedResultsController<Post>
var tableView:UITableView = {
return UITableView()
}()
override func viewDidLoad(){
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
let fetchRequest:NSFetchRequest<Post> = Post.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "foo = %@ and bar = %@", argumentArray: ["baz", "loreum"])
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Post.createdAt), ascending: false)]
self.fetchedResultController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: context,
sectionNameKeyPath: #keyPath(Post.createdAt),
cacheName: nil)
self.fetchedResultController.delegate = self
do {
try self.fetchedResultController.performFetch()
} catch let error as NSError {
fatalError("Error: \(error.localizedDescription)")
}
}
// MARK - NSFetchedResultsControllerDelegate
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { /** do stuff **/ }
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { /** do stuff **/ }
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
tableView.insertSections(IndexSet(integer: sectionIndex), with: .left)
case .delete:
tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
default:
break;
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { /** do stuff **/ }
// MARK - UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController.sections?.count ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { /** do stuff **/ }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "my-cell-identifier", for: indexPath) as! CustomUITableViewCell
configureCell(cell, indexPath: indexPath)
return cell
}
// MARK - Cell configuration
func configureCell(_ cell:CustomUITableViewCell, indexPath:IndexPath){
let o = fetchedResultsController.object(at: indexPath)
cell.textLabel?.text = o.userName
// configure cell more here
}
}
【问题讨论】:
-
在我看来,没有简单的方法可以将 MVVM 与 CoreData 结合起来。如果必须,您的 ViewModel 可以管理您的 FRC,同时为您的 ViewController 提供回调,这些回调映射到您的 FRC 委托方法。另一方面,如果您要使用 Realm,我发现它比 CoreData 更适合 MVVM。但我不确定你的要求是什么。
标签: ios swift uitableview core-data mvvm