bar*_*bus 6 core-data uitableview nsfetchedresultscontroller ios swift
现在已经挣扎了两个星期而没有找到足够的教程,SO通过我自己的许多失败的调查回答任何问题,我觉得最好在这里问一下,看看是否可以提供一个好的答案,或许可以节省我自己和很多其他人时间和头痛!
许多指南建议使用NSFetchedResultsController从Core Data存储中检索数据,特别是如果要在UITableView中显示数据.然而,几乎所有教程都假设您希望一次显示所有数据并停在那里.一旦我试图限制单元格数量并实现"加载更多"功能,它就会在接缝处开始崩溃.
在以下代码中(在Swift中实现),使用AFNetworking从API检索数据并将其保存到Core Data.保存数据发生在AF呼叫的成功块中.
所有这些都有效,但我无法找到一种成功的方法来限制显示的项目/单元格的数量,并在用户向下滚动时增加它.
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)")
}
}
Run Code Online (Sandbox Code Playgroud)
我试过的方法包括:
经过很长一段时间玩这些并研究它们,它们看起来像内存优化,并且对表视图显示的数据没有影响.绝对不是正确的道路.
使用以下内容仍然可以在cellForRowAtIndexPath中显示数据:
func configureCell(cell: SearchResultCell, atIndexPath indexPath: NSIndexPath)
{
let entity = self.fFetchedResultsController.objectAtIndexPath(indexPath) as Entity
...
}
Run Code Online (Sandbox Code Playgroud)
也许这是正确的方法,但我实施错了?
这会导致填充单元格时EXC_BAD_ACCESS崩溃,但重新加载应用程序后,它会正确显示数据.
我真的很想坚持NSFetchedResultsController,因为我相信它有一些强大的排序/谓词功能,我想在我的应用程序中利用,但我目前陷入僵局.提前道歉,如果这已经在其他地方明确回答,但我无法找到这样的,并且非常感谢任何输入.
归档时间: |
|
查看次数: |
1580 次 |
最近记录: |