这是我的Message.swift
文件:
@objc(Message)
class Message: NSManagedObject {
@NSManaged var content: String
@NSManaged var createdAt: NSDate
@NSManaged var identifier: Int64
@NSManaged var conversation: Conversation
@NSManaged var sender: Contributor
var normalizedCreatedAt: NSDate {
return createdAt.dateWithDayMonthAndYearComponents()!
}
}
这就是我设置FRC的方式:
private func setupFetchedResultsController() {
let context = NSManagedObjectContext.MR_defaultContext()
let fetchRequest = NSFetchRequest(entityName: "Message")
let createdAtDescriptor = NSSortDescriptor(key: "createdAt", ascending: true)
fetchRequest.predicate = NSPredicate(format: "conversation.identifier = %lld", conversation.identifier)
fetchRequest.sortDescriptors = [createdAtDescriptor]
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: "normalizedCreatedAt", cacheName: nil)
fetchedResultsController.delegate = self
try! fetchedResultsController.performFetch()
tableView.reloadData()
}
及其标准代表。
在viewDidLoad
我的控制器有1个部分,有1行。我使用以下功能在控制台上打印它:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("--->>>")
print(section)
print(fetchedResultsController.sections![section].objects!.count)
return fetchedResultsController.sections![section].objects!.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultsController?.sections?.count ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let message = fetchedResultsController?.objectAtIndexPath(indexPath) as! Message
let cellIdentifier = message.sender.identifier == Settings.currentUser?.profile?.identifier ? SentTableViewCellIdentifier : ReceivedTableViewCellIdentifier
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TableViewCell
cell.cellTitleLabel?.text = message.content
return cell
}
,输出如下:
--->>>
0
1
一旦我尝试添加另一个不同部分的消息,我得到以下信息:
--->>>
0
2
--->>>
1
1
然后是错误:
CoreData:错误:严重的应用程序错误。在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托中捕获到异常。无效更新:第0节中的行数无效。更新(2)后现有部分中包含的行数必须等于更新前该部分中包含的行数(1),加上或减去数字从该部分插入或删除的行(0插入,0删除)和加或减移入或移出该部分的行数(0移入,0移出)。 with userInfo(null)
为什么会这样?
NSFetchedResultsController
由于某种原因将相同的单元格加载到两个部分:第一个和第二个。为什么呢?
注意:
答案 0 :(得分:1)
我尝试了你的代码,只做了一次改动,这个:
var normalizedCreatedAt: String {
return getTimeStrWithDayPrecision(createdAt!)
}
func getTimeStrWithDayPrecision(date: NSDate) -> String {
let formatter = NSDateFormatter()
formatter.timeStyle = .NoStyle
formatter.dateStyle = .ShortStyle
formatter.doesRelativeDateFormatting = true
return formatter.stringFromDate(date)
}
它工作正常,即使是第2部分也是如此!
出于演示目的,我添加了ADD
按钮,按下它,代码会将当前日期字符串为content
的新消息添加到DB。
这是我的完整实施: 查看控制器 -
class ChatTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
private var fetchedResultsController: NSFetchedResultsController?
private var _mainThreadMOC: NSManagedObjectContext?
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
setupFetchedResultsController()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func getMainMOC() -> NSManagedObjectContext {
if _mainThreadMOC == nil {
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
_mainThreadMOC = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
_mainThreadMOC!.persistentStoreCoordinator = appDel.persistentStoreCoordinator
_mainThreadMOC!.undoManager = nil
}
return _mainThreadMOC!
}
private func setupFetchedResultsController() {
let fetchRequest = NSFetchRequest(entityName: "Message")
let createdAtDescriptor = NSSortDescriptor(key: "createdAt", ascending: true)
fetchRequest.sortDescriptors = [createdAtDescriptor]
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: getMainMOC(), sectionNameKeyPath: "normalizedCreatedAt", cacheName: nil)
fetchedResultsController!.delegate = self
try! fetchedResultsController!.performFetch()
tableView.reloadData()
}
@IBAction func addMessage(sender: AnyObject) {
print("addMessage")
let MOC = getMainMOC()
let date = NSDate()
let _ = Message(text: "\(date)", moc: MOC)
do {
try MOC.save()
}catch {
print("Error saving main MOC: \(error)")
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultsController?.sections?.count ?? 0
}
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let sectionInfo = fetchedResultsController!.sections! as [NSFetchedResultsSectionInfo]
let title = sectionInfo[section].name
let headerHeight:CGFloat = tableView.sectionHeaderHeight
let headerLbl = UILabel(frame: CGRectMake(0, 0, tableView.frame.width, headerHeight))
headerLbl.backgroundColor = UIColor.lightGrayColor()
headerLbl.textAlignment = .Center
headerLbl.text = title
return headerLbl
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("--->>>")
print(section)
print(fetchedResultsController?.sections![section].objects!.count)
return (fetchedResultsController?.sections![section].objects!.count)!
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let message = fetchedResultsController?.objectAtIndexPath(indexPath) as! Message
let cell = tableView.dequeueReusableCellWithIdentifier("MessageCellId", forIndexPath: indexPath)
cell.textLabel?.text = message.content!
return cell
}
//MARK: - NSFetchedResultsControllerDelegate
func controllerWillChangeContent(controller: NSFetchedResultsController) {
tableView.beginUpdates()
}
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
let indexSet = NSIndexSet(index: sectionIndex)
switch type {
case .Insert:
tableView.insertSections(indexSet, withRowAnimation: .Fade)
case .Delete:
tableView.deleteSections(indexSet, withRowAnimation: .Fade)
case .Update:
fallthrough
case .Move:
tableView.reloadSections(indexSet, withRowAnimation: .Fade)
}
}
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case .Insert:
if let newIndexPath = newIndexPath {
tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
}
case .Delete:
if let indexPath = indexPath {
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
case .Update:
if let indexPath = indexPath {
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
case .Move:
if let indexPath = indexPath, let newIndexPath = newIndexPath {
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
}
}
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
tableView.endUpdates()
}
}
消息 -
func getTimeStrWithDayPrecision(date: NSDate) -> String {
let formatter = NSDateFormatter()
formatter.timeStyle = .NoStyle
formatter.dateStyle = .ShortStyle
formatter.doesRelativeDateFormatting = true
return formatter.stringFromDate(date)
}
extension Message {
@NSManaged var content: String?
@NSManaged var createdAt: NSDate?
var normalizedCreatedAt: String {
return getTimeStrWithDayPrecision(createdAt!)
}
}
class Message: NSManagedObject {
// Insert code here to add functionality to your managed object subclass
override init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?) {
super.init(entity: entity, insertIntoManagedObjectContext: context)
}
init(text: String, moc:NSManagedObjectContext) {
let entity = NSEntityDescription.entityForName("Message", inManagedObjectContext: moc)
super.init(entity: entity!, insertIntoManagedObjectContext: moc)
content = text
createdAt = NSDate()
}
}
为了测试多个部分,我改变了日期和时间。时间设置os iPad。
答案 1 :(得分:0)
我不知道为什么,但要使其正常工作,您需要更换:
fetchedResultsController.sections![section].objects!.count
与
fetchedResultsController.sections![section].numberOfObjects
由于某种原因,objects!.count
会返回与<{1}}属性相对的不正确的对象数。