2016-04-25 130 views
0

我幾乎完成了我的第一個iOS應用程序,但有一個問題從正在從核心數據填充的表視圖中刪除。核心數據實體具有4個顯示在單元中的屬性。我試圖遵循的所有示例都使用一個歸因實體。另外我有兩種類型的描述。不知道這是否對我的問題有任何影響。我的tableview正確填入..編輯選項可用,但一旦行被選中並刪除感動我得到一個錯誤,調試器停止在該行class AppDelegate: UIResponder, UIApplicationDelegate {和Xcode的輸出以下Swift UITableView刪除行項目 - tableview數據源是核心數據

2016-04-25 20:00:05.739 MileageLogger[41673:17841244] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.60.7/UITableView.m:1716 
2016-04-25 20:00:05.768 MileageLogger[41673:17841244] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (14) must be equal to the number of rows contained in that section before the update (14), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).' 
*** First throw call stack: 
(
    0 CoreFoundation      0x00633494 __exceptionPreprocess + 180 
    1 libobjc.A.dylib      0x02347e02 objc_exception_throw + 50 
    2 CoreFoundation      0x0063332a +[NSException raise:format:arguments:] + 138 
    3 Foundation       0x00a78322 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 118 
    4 UIKit        0x00f7b014 -[UITableView _endCellAnimationsWithContext:] + 17170 
    5 UIKit        0x00f94216 -[UITableView _updateRowsAtIndexPaths:updateAction:withRowAnimation:] + 363 
    6 UIKit        0x00f942a4 -[UITableView deleteRowsAtIndexPaths:withRowAnimation:] + 56 
    7 UIKit        0x0fec584a -[UITableViewAccessibility deleteRowsAtIndexPaths:withRowAnimation:] + 65 
    8 MileageLogger      0x00062789 _TFC13MileageLogger30MileageLogsTableViewController9tableViewfTCSo11UITableView18commitEditingStyleOSC27UITableViewCellEditingStyle17forRowAtIndexPathCSo11NSIndexPath_T_ + 201 
    9 MileageLogger      0x00062827 _TToFC13MileageLogger30MileageLogsTableViewController9tableViewfTCSo11UITableView18commitEditingStyleOSC27UITableViewCellEditingStyle17forRowAtIndexPathCSo11NSIndexPath_T_ + 103 
    10 UIKit        0x00fafc94 -[UITableView animateDeletionOfRowWithCell:] + 185 
    11 UIKit        0x00f80ce5 __52-[UITableView _swipeActionButtonsForRowAtIndexPath:]_block_invoke + 110 
    12 UIKit        0x00fb17f3 -[UITableView _actionButton:pushedInCell:] + 178 
    13 UIKit        0x0121cc68 -[UITableViewCell _actionButtonPushed:] + 88 
    14 libobjc.A.dylib      0x0235c0b5 -[NSObject performSelector:withObject:withObject:] + 84 
    15 UIKit        0x00e23e38 -[UIApplication sendAction:to:from:forEvent:] + 118 
    16 UIKit        0x00e23db7 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 64 
    17 UIKit        0x00fc7f3b -[UIControl sendAction:to:forEvent:] + 79 
    18 UIKit        0x00fc82d4 -[UIControl _sendActionsForEvents:withEvent:] + 433 
    19 UIKit        0x00fc72c1 -[UIControl touchesEnded:withEvent:] + 714 
    20 UIKit        0x013aad2e _UIGestureRecognizerUpdate + 12763 
    21 UIKit        0x00ea3efd -[UIWindow _sendGesturesForEvent:] + 1559 
    22 UIKit        0x00ea55b6 -[UIWindow sendEvent:] + 1137 
    23 UIKit        0x00e46be8 -[UIApplication sendEvent:] + 266 
    24 UIKit        0x0febc369 -[UIApplicationAccessibility sendEvent:] + 72 
    25 UIKit        0x00e1b769 _UIApplicationHandleEventQueue + 7795 
    26 CoreFoundation      0x00545e5f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15 
    27 CoreFoundation      0x0053baeb __CFRunLoopDoSources0 + 523 
    28 CoreFoundation      0x0053af08 __CFRunLoopRun + 1032 
    29 CoreFoundation      0x0053a846 CFRunLoopRunSpecific + 470 
    30 CoreFoundation      0x0053a65b CFRunLoopRunInMode + 123 
    31 GraphicsServices     0x04b2f664 GSEventRunModal + 192 
    32 GraphicsServices     0x04b2f4a1 GSEventRun + 104 
    33 UIKit        0x00e21eb9 UIApplicationMain + 160 
    34 MileageLogger      0x00055201 main + 145 
    35 libdyld.dylib      0x02d67a25 start + 1 
) 
libc++abi.dylib: terminating with uncaught exception of type NSException 

我的代碼是TableViewController是...

import UIKit 
import CoreData 

class MileageLogsTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { 

    @IBOutlet var milageLogTableView: UITableView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     do { 
      try fetchedResultsController.performFetch() 
     } catch { 
      let fetchError = error as NSError 
      print("Unable to fetch MileageLog") 
      print("\(fetchError), \(fetchError.localizedDescription)") 
     } 

     // Display an Edit button in the navigation bar for this view controller. 
     self.navigationItem.leftBarButtonItem = self.editButtonItem() 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    // MARK: - Table view data source 

    private lazy var fetchedResultsController: NSFetchedResultsController = { 
     // Initialize Fetch Request 
     let fetchRequest = NSFetchRequest(entityName: "MileageLog") 

     // Add Sort Descriptors 
     let dateSort = NSSortDescriptor(key: "tripDate", ascending: false) 
     let mileSort = NSSortDescriptor(key: "startMileage", ascending: false) 
     fetchRequest.sortDescriptors = [dateSort, mileSort] 

     let delegate = UIApplication.sharedApplication().delegate as! AppDelegate 
     let managedObjectContext = delegate.managedObjectContext 

     // Initialize Fetched Results Controller 
     let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: "rootCache") 

     return fetchedResultsController 

    }() 

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
     if let sections = fetchedResultsController.sections { 
      return sections.count 
     } 

     return 0 
    } 

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     if let sections = fetchedResultsController.sections { 
      let sectionInfo = sections[section] 
      return sectionInfo.numberOfObjects 
     } 

     return 0 
    } 


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

     let cell = tableView.dequeueReusableCellWithIdentifier("MileageLogCell") as! MileageTableViewCell 

     // Fetch MileageLog 
     if let mileageLog = fetchedResultsController.objectAtIndexPath(indexPath) as? MileageLog { 
      //format date as medium style date 
      let formatter = NSDateFormatter() 
      formatter.dateStyle = .MediumStyle 
      let logDateString = formatter.stringFromDate(mileageLog.tripDate!) 
      //format NSNumber mileage to string 
      let mileageInt:NSNumber = mileageLog.startMileage! 
      let mileageString = String(mileageInt) 

      cell.lb_LogDate.text = logDateString 
      cell.lb_LogMileage.text = mileageString 
      cell.lb_LogStartLocation.text = mileageLog.startLocation 
      cell.lb_LogDestination.text = mileageLog.endLocation 
     } 
     return cell 
    } 


    // Override to support conditional editing of the table view. 
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { 
     // Return false if you do not want the specified item to be editable. 
     return true 
    } 

    // Override to support editing the table view. 
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { 

     switch editingStyle { 

     case .Delete: 
      // Delete the row from the data source 
      tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) 

     default : 
      return 
     } 

    } 
} 

我正在努力尋找解決方案...任何幫助表示讚賞。

+0

你可以寫FUNC controllerWillChangeContent(控制器:NSFetchedResultsController){ tableView.beginUpdates() } FUNC controllerDidChangeContent(控制器:NSFetchedResultsController){ tableView.endUpdates() } –

+0

我認爲你必須編輯的數據源首先與您的新顯示行保持一致。也許把數據放到一個數組中,在調用deleteRows之前刪除相關的索引。不幸的是,當它在一個fetchedResultsController中時,我不知道如何改變dataSource。不幸的是, –

+0

@Mych:最簡單,但一個小小的代價就是調用self。 tableView.reloadData()在刪除的情況下:) –

回答

4

deleteRowsAtIndexPaths只更新視圖,而不是模型,你也必須刪除對象的核心數據

... 
    case .Delete: 
     // Delete the row from the data source 
     let objectToDelete = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject 
     let context = fetchedResultsController.managedObjectContext 
     context.deleteObject(objectToDelete) 
     do { 
      try context.save() 
      tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) 
     } catch { 
      print(error) 
     } 

當使用NSFetchedResultsController它強烈建議實現委託方法來處理用戶界面的更新那裏。

+0

瓦迪亞,感謝作出改變,建議刪除。我仍然收到類似的錯誤。由於未捕獲異常'NSInternalInconsistencyException'而終止應用程序,原因如下:'無效更新:第0節中的行數無效。更新(13)後現有節中包含的行數必須等於該節中包含的行數更新前的部分(13),加上或減去從該部分插入或刪除的行數(0插入,1刪除),加上或減去移入或移出該部分的行數(0移入,0移入出)。」 – Mych

+0

注意我現在只有13行...之前我有14個。所以它看起來像核心數據被刪除,但tableview無法更新。 – Mych

+0

現在您需要實現'NSFetchedResultsControllerDelegate'方法,以便您可以通知操作的表視圖。 –