Ios 使用NSFetchedResultsController和UITableView(Swift)限制显示结果
现在我已经为此挣扎了两周,没有找到足够的教程,所以通过我自己的许多失败的调查,我觉得最好在这里问一下,看看是否可以提供一个好的答案,也许可以节省我自己和许多其他人很多时间和头痛 许多指南建议使用NSFetchedResultsController从核心数据存储中检索数据,特别是如果您希望在UITableView中显示数据。然而,几乎所有的教程都假设您希望一次显示所有数据,然后到此为止。例如,当我试图限制单元格的数量并实现“加载更多”功能时,所有这些都开始在接缝处崩溃 在以下代码中(在Swift中实现),使用AFNetworking从API检索数据并保存到核心数据。数据的保存发生在AF调用的成功块中 所有这些都有效,但我无法找到一种成功的方法来限制显示的项目/单元格的数量,并在用户向下滚动时增加它Ios 使用NSFetchedResultsController和UITableView(Swift)限制显示结果,ios,uitableview,swift,core-data,nsfetchedresultscontroller,Ios,Uitableview,Swift,Core Data,Nsfetchedresultscontroller,现在我已经为此挣扎了两周,没有找到足够的教程,所以通过我自己的许多失败的调查,我觉得最好在这里问一下,看看是否可以提供一个好的答案,也许可以节省我自己和许多其他人很多时间和头痛 许多指南建议使用NSFetchedResultsController从核心数据存储中检索数据,特别是如果您希望在UITableView中显示数据。然而,几乎所有的教程都假设您希望一次显示所有数据,然后到此为止。例如,当我试图限制单元格的数量并实现“加载更多”功能时,所有这些都开始在接缝处崩溃 在以下代码中(在Swift中
import UIKit
import CoreData
class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, CLLocationManagerDelegate, NSFetchedResultsControllerDelegate{
@IBOutlet var tableView: UITableView!
// TableView Properties
private let cellIdentifier = "SearchResultCellIdentifier"
var refreshController = UIRefreshControl()
// persistant data stores and controllers
private var managedObjectContext : NSManagedObjectContext?
private var displayCount = 5
// Setup the fetch results controller
var fetchedResultsController: NSFetchedResultsController
{
if _fetchedResultsController != nil
{
return _fetchedResultsController!
}
let fetchRequest = NSFetchRequest()
// Edit the entity name as appropriate.
let entity = NSEntityDescription.entityForName("Entity", inManagedObjectContext: self.managedObjectContext!)
fetchRequest.entity = entity
fetchRequest.fetchBatchSize = 25
fetchRequest.fetchLimit = 25
let sortDescriptor = NSSortDescriptor(key: "name", 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: nil, cacheName: nil)
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
var error: NSError? = nil
if !_fetchedResultsController!.performFetch(&error)
{
println("fetch error: \(error!.localizedDescription)")
abort()
}
return _fetchedResultsController!
}
var _fetchedResultsController: NSFetchedResultsController? = nil
override func viewDidLoad()
{
super.viewDidLoad()
// setup table view delegate and datasource
self.tableView.dataSource = self
self.tableView.delegate = self
// pull-to-refresh setup
self.refreshController.addTarget(self, action: "refreshTable:", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(self.refreshController)
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
// Return the number of sections.
return 1
}
// ask the NSFetchedResultsController for the section
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let info = self.fetchedResultsController.sections![section] as NSFetchedResultsSectionInfo
return info.numberOfObjects
}
// create and configure each 'UITableViewCell'
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier(self.cellIdentifier, forIndexPath: indexPath) as SearchResultCell
self.configureCell(cell, atIndexPath: indexPath)
return cell
}
// helper method to configure a UITableViewCell ask NSFetchedResultsController for the model
func configureCell(cell: SearchResultCell, atIndexPath indexPath: NSIndexPath)
{
let entity = self.fetchedResultsController.objectAtIndexPath(indexPath) as Entity
cell.title.text = entity.name
}
// MARK: NSFetchedResultsController Delegate functions
func controllerWillChangeContent(controller: NSFetchedResultsController)
{
self.tableView.beginUpdates()
}
func controllerDidChangeContent(controller: NSFetchedResultsController)
{
self.tableView.endUpdates()
self.tableView.reloadData()
self.refreshController.endRefreshing()
}
/* Delegate method called:
- when a new model is created
- when an existing model is updated
- when an existing model is deleted
*/
func controller(controller: NSFetchedResultsController,
didChangeObject object: AnyObject,
atIndexPath indexPath: NSIndexPath,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath)
{
switch type
{
case .Insert:
self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
case .Update:
let cell = self.tableView.cellForRowAtIndexPath(indexPath)
self.configureCell(cell! as SearchResultCell, atIndexPath: indexPath)
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
case .Move:
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
case .Delete:
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
default:
return
}
}
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
{
switch type
{
case .Insert:
println("DEBUG: INSERT SECTION")
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
break
case .Delete:
println("DEBUG: DELETE SECTION")
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
default:
return
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
// MARK: Core Data Stack
/**
Save results response from server to CoreData entities
*/
private func saveSearchResultsResponse(response: AnyObject)
{
self.deleteAllEntities("Entity")
println("DEBUG: Saving new objects to model")
// Search results object from response
if let searchResultsDict = response as? [String: AnyObject]
{
if let entities = searchResultsDict["entities"] as? [AnyObject]
{
if let attributes = NSEntityDescription.entityForName("Entity", inManagedObjectContext: self.managedObjectContext!)?.attributesByName
{
// save entities
}
}
}
}
// save changes persistent store
var error : NSError?
if !(self.managedObjectContext!.save(&error))
{
println("ERROR: Error saving model: \(error?.localizedDescription)")
}
}
func deleteAllEntities(entityName: String)
{
var error: NSError? = nil
let allEntityFetchRequest = NSFetchRequest(entityName: entityName)
if let savedObjects = self.managedObjectContext?.executeFetchRequest(allEntityFetchRequest, error: &error) as? [NSManagedObject]
{
for object in savedObjects
{
self.managedObjectContext?.deleteObject(object as NSManagedObject)
}
// save changes persistent store
if !(self.managedObjectContext!.save(&error))
{
println("ERROR: Error saving model: \(error?.localizedDescription)")
}
}
else
{
println("ERROR: Fetch error: \(error!.localizedDescription)")
}
}
我尝试过的方法包括:
- 获取批大小
- 取数限制
func configureCell(cell: SearchResultCell, atIndexPath indexPath: NSIndexPath)
{
let entity = self.fFetchedResultsController.objectAtIndexPath(indexPath) as Entity
...
}
也许这是正确的方法,但我实施的方式是错误的
我真的很想坚持使用NSFetchedResultsController,因为我相信它有一些强大的排序/谓词功能,我想在我的应用程序中加以利用,但我目前在这方面陷入僵局。如果其他地方已经明确回答了,请提前道歉,但我无法找到这样的答案,非常感谢您的任何意见。方法2是我在阅读您的问题时想到的技巧。您应该只需要像您所说的那样保留一个“count”,并在为行“count-1”调用
willDisplayCellForIndexPath:
时增加它,并且count是