在Realm结果更新时,TableView抛出NSInternalInconsistencyException

时间:2016-11-16 21:15:26

标签: uitableview swift3 realm

我在Swift中遇到了Realm result set的问题。每当Realm结果更新时,我都使用Realm通知块来更新我的TableView。

但是,在更新TableView期间,有时会将新项添加到Realm结果中,从而导致NSInternalInconsistencyException

我的环境:

情境:

因此,我想发送一条聊天消息,同时也会收到一条聊天消息。

  1. 我正在添加我发送给Realm数据库的消息。
  2. My Realm通知块将开始更新TableView。
  3. 与此同时,我收到某人的聊天消息,并将其添加到Realm数据库中。
  4. TableView更新已完成并抛出NSInternalInconsistencyException,因为Realm在更新开始时的结果大小与更新结束时的大小不同(因为收到的消息已添加到Realm中)数据库)。
  5. 抛出的异常:

    2016-11-16 21:03:57.727510 MyApp[9042:2331360] *** 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 (98) must be equal to the number of rows contained in that section before the update (97), plus or minus the number of rows inserted or deleted from that section (10 inserted, 10 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:
    (0x18f5021c0 0x18df3c55c 0x18f502094 0x18ff8f79c 0x19554001c 0x1000faeb8 0x10137619c 0x10134d4d0 0x100bf4b88 0x100bf4754 0x100b427fc 0x100b425f0 0x100ba0004 0x100d3072c 0x100d878b8 0x100d8840c 0x100d883e4 0x18f4b0278 0x18f4afbc0 0x18f4ad7c0 0x18f3dc048 0x190e62198 0x1953c82fc 0x1953c3034 0x100105be8 0x18e3c05b8)
    libc++abi.dylib: terminating with uncaught exception of type NSException
    

    重现的步骤:

    1. 创建一个TableView控制器。
    2. 使用realm.objects(ChatMessage.self)获取一些结果。
    3. 使用Realm collection notification更新TableView。
    4. 使用0.1秒的间隔向Realm添加新消息。
    5. 构建并运行该应用程序。
    6. 等待几秒钟,应用程序崩溃并显示NSInternalInconsistencyException
    7. 我的视图控制器:

      这是导致崩溃的代码。

      import UIKit
      import RealmSwift
      import Alamofire
      import AlamofireObjectMapper
      
      class ChatTestViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
      
          @IBOutlet weak var tableView: UITableView!
      
          let realm =  try! Realm()
      
          let textCellMeIdentifier = "ChatMessageCellMe"
      
          var results: Results<ChatMessage>?
      
          var ticket: Ticket?
      
          var notificationToken: NotificationToken?
      
          var tableViewTempCount = 0
      
          override func viewDidLoad() {
              super.viewDidLoad()
      
              ticket = realm.objects(Ticket.self).first
              results = realm.objects(ChatMessage.self)
      
              initializeTableView()
      
              notificationToken = results?.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
                  guard let tableView = self?.tableView else { return }
      
                  switch changes {
                  case .initial:
                      tableView.reloadData()
                      break
                  case .update(_, let deletions, let insertions, let modifications):
                      tableView.beginUpdates()
                      tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }), with: .none)
                      tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}), with: .none)
                      tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }), with: .none)
                      tableView.endUpdates()
                      break
                  case .error(let error):
                      fatalError("\(error)")
                      break
                  }
              }
      
              _ = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.sendRandomMessage), userInfo: nil, repeats: true)
          }
      
          deinit {
              notificationToken?.stop()
          }
      
          private func initializeTableView() {
              tableView.register(UINib(nibName: textCellMeIdentifier, bundle: Bundle.main), forCellReuseIdentifier: textCellMeIdentifier)
      
              tableView.delegate = self
              tableView.dataSource = self
          }
      
          @objc func sendRandomMessage() {
              tableViewTempCount += 1
      
              let parameters: Parameters = [
                  "body": "Random Test: " + String(describing: tableViewTempCount),
              ]
      
              let tempMessage = ChatMessage()
              tempMessage.id = "-" + String(describing: tableViewTempCount)
              tempMessage.ticketId = ticket!.id
              tempMessage.sent = false
              tempMessage.body = parameters["body"]! as! String
              tempMessage.by = ChatMessage.By.me.rawValue
              tempMessage.createdAt = Date()
      
              let realm = try! Realm()
      
              try! realm.write {
                  /// Add a temporary message to the TableView (and remove it if the server returned the saved message)
                  realm.add(tempMessage, update: true)
      
      //            _ = ChatMessageClient.create(ticket!, parameters) { (error: Error?, chatMessages: [ChatMessage]?) in
      //                /// The server responded with the message and it was inserted in our Realm database, so delete the temp message
      //                realm.delete(tempMessage)
      //            }
              }
          }
      
          func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
              return results!.count
          }
      
          func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
              let row = results?[indexPath.row]
      
              let cell:ChatMessageCell = (tableView.dequeueReusableCell(withIdentifier: textCellMeIdentifier, for: indexPath as IndexPath) as? ChatMessageCell)!
      
              cell.body.text = row?.body
              cell.container.alpha = (row?.sent)! ? 1.0 : 0.4
      
              return cell
          }
      
      }
      

      我希望有人可以帮我防止抛出此异常。

1 个答案:

答案 0 :(得分:2)

我们最近在Realm的收集通知机制中修复了一些竞争条件,这可能导致您在此处看到的异常。见https://realm.io/news/realm-objc-swift-2.1/

请您再试一次Realm Swift 2.1.0,如果它可以解决您的问题,请告诉我们?谢谢!