' NSInternalInconsistencyException'使用Collection View Swift 3插入项目

时间:2017-02-28 04:56:52

标签: ios swift uicollectionview realm xcode8

所以,我使用Realm作为数据存储,我非常确定在集合视图中的索引路径中插入项目之前,我需要首先添加内容。但我一直都知道这个太熟悉的错误:

'NSInternalInconsistencyException', reason: 'attempt to insert item 1 into section -1, but there are only 1 items in section 1 after the update'

这是我的模特:

final class Listing: Object {
dynamic var id = ""
dynamic var name = ""
dynamic var item = ""

}

这是我的视图控制器,它符合UICollectionView数据源和委托:

 override func viewDidLoad() {
    super.viewDidLoad()

    // MARK: - Get Listings!

    queryListings()

    // MARK: - Delegates

    self.collectionView.delegate = self
    self.collectionView.dataSource = self
}

// MARK: - Query Listings

func queryListings() {
    let realm = try! Realm()

    let everyListing = realm.objects(Listing.self)
    let listingDates = everyArticle.sorted(byKeyPath: "created", ascending: false)

    for listing in listingDates {
        listing.append(listing)
        self.collectionView.performBatchUpdates({ 
            self.collectionView.insertItems(at: [IndexPath(item: self.listing.count, section: 1)])
        }, completion: nil)
    }
}

代表:

 // MARK: UICollectionViewDataSource

 func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}

 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return listing.count
}

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! ListingCollectionViewCell

    cell.awakeFromNib()

    return cell
}

我已尝试过self.listing.count 0,1,-1,+ 1以及0,1,-1,+ 1的每个排列,并且引发的异常相同加或减部分和存在的项目。调用reloadData()也没有帮助。

有人用集合视图解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

<强>解决

使用Realm,心态与我习惯的不同 - 你正在操纵影响表或集合的数据,而不是直接操作表或集合。听起来很明显,但是......无论如何,TiM的答案是正确的。这是集合视图版本:

// MARK: - Observe Results Notifications

    notificationToken = articles.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in

        guard (self?.collectionView) != nil else { return }

        // MARK: - Switch on State

        switch changes {

        case .initial:
            self?.collectionView.reloadData()
            break
        case .update(_, let deletions, let insertions, let modifications):
            self?.collectionView.performBatchUpdates({
                self?.collectionView.insertItems(at: insertions.map({ IndexPath(row: $0, section: 0)}))
                self?.collectionView.deleteItems(at: deletions.map({ IndexPath(row: $0, section: 0)}))
                self?.collectionView.reloadItems(at: modifications.map({ IndexPath(row: $0, section: 0)}))
            }, completion: nil)
            break
        case .error(let error):
            print(error.localizedDescription)
            break
        }
    }

答案 1 :(得分:0)

代码行for listing in listingDates { listing.append(listing) }似乎有点不安全。您要么指的是名为listing的单独对象(例如类属性),要么引用相同的listing对象。如果列表是Realm Results对象,则无法在其上调用append

无论如何,你可能做的工作比你需要的多一点。领域对象,无论它们是Object还是Results都是实时的,因为它们会在基础数据更改它们时自动更新。因此,没有必要执行多个查询来更新集合视图。

最佳做法是执行一次查询,并将Results对象另存为视图控制器的属性。从那时起,您可以使用Realm's Change Notification功能来指定每次Realm查询更改时都会执行的Swift闭包。然后,可以使用它来为集合视图上的更新设置动画:

class ViewController: UITableViewController {
  var notificationToken: NotificationToken? = nil

  override func viewDidLoad() {
    super.viewDidLoad()
    let realm = try! Realm()
    let results = realm.objects(Person.self).filter("age > 5")

    // Observe Results Notifications
    notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
      guard let tableView = self?.tableView else { return }
      switch changes {
      case .initial:
        // Results are now populated and can be accessed without blocking the UI
        tableView.reloadData()
        break
      case .update(_, let deletions, let insertions, let modifications):
        // Query results have changed, so apply them to the UITableView
        tableView.beginUpdates()
        tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }),
                           with: .automatic)
        tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}),
                           with: .automatic)
        tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }),
                           with: .automatic)
        tableView.endUpdates()
        break
      case .error(let error):
        // An error occurred while opening the Realm file on the background worker thread
        fatalError("\(error)")
        break
      }
    }
  }

  deinit {
    notificationToken?.stop()
  }
}
相关问题