ios - NSFetchedResultsController inserts the same cell into two sections only when controller is about to insert another section -


this message.swift file:

@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()!     } } 

this how setup 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() } 

with standard delegate.

on viewdidload controller has 1 section 1 row. print on console using following function:

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 } 

and output following:

--->>> 0 1 

once try add 1 message different section, following get:

--->>> 0 2 --->>> 1 1 

and error:

coredata: error: serious application error. exception caught delegate of nsfetchedresultscontroller during call -controllerdidchangecontent:. invalid update: invalid number of rows in section 0. number of rows contained in existing section after update (2) must equal number of rows contained in section before update (1), plus or minus number of rows inserted or deleted section (0 inserted, 0 deleted) , plus or minus number of rows moved or out of section (0 moved in, 0 moved out). userinfo (null)

why happens that?

nsfetchedresultscontroller reason loads same cell 2 sections: first , second. why?

note:

  • the problem arise when frc insert new section. if needs insert row existing section, there no problem. issue strong related sections.
  • the problem when frc try insert second section. when third or fourth section, there no problem @ all.

i tried code, made 1 change, this:

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) } 

and works fine, 2nd section also!

for demo purpose, added add button, pressing it, code add new message current date string content db.

here complete implementation: view controller-

class chattableviewcontroller: uitableviewcontroller, nsfetchedresultscontrollerdelegate {   private var fetchedresultscontroller: nsfetchedresultscontroller? private var _mainthreadmoc: nsmanagedobjectcontext?  override func viewdidload() {     super.viewdidload()      // uncomment following line preserve selection between presentations     // self.clearsselectiononviewwillappear = false      // uncomment following line display edit button in navigation bar view controller.     // self.navigationitem.rightbarbuttonitem = self.editbuttonitem()      setupfetchedresultscontroller() }  override func didreceivememorywarning() {     super.didreceivememorywarning()     // dispose of resources can 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)     {         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! [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() } } 

message-

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 add functionality 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() } } 

here ipad screenshot:
enter image description here

for testing multiple sections, changed date & time setting os ipad.


Comments

Popular posts from this blog

amazon web services - S3 Pre-signed POST validate file type? -

c# - Check Keyboard Input Winforms -