So, I am using Realm as a data store, which I'm pretty sure I need to first add content to before inserting an item at index path in a collection view. But I keep getting this all too familiar error:
'NSInternalInconsistencyException', reason: 'attempt to insert item 1 into section -1, but there are only 1 items in section 1 after the update'
Here is my model:
final class Listing: Object {
dynamic var id = ""
dynamic var name = ""
dynamic var item = ""
}
Here is my view controller that conforms to UICollectionView data sources and delegates:
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)
}
}
Delegates:
// 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
}
I've tried every permutation of self.listing.count 0, 1, -1 , +1 as well as section 0, 1, -1, +1 and the exception raised is the same plus or minus the section and items that exist. Calling reloadData() doesn't help either.
Anyone solve this with a collection view?
The lines of code for listing in listingDates { listing.append(listing) }
seem a bit unsafe. Either you're referring to separate objects named listing
(such as a class property), or that's in reference to the same listing
object. If listing is a Realm Results
object, it shouldn't be possible to call append
on it.
In any case, you're probably doing a bit more work than you need to. Realm objects, whether they are Object
or Results
are live, in that they'll automatically update if the underlying data changes them. As such, it's not necessary to perform multiple queries to update a collection view.
Best practice is to perform the query once, and save the Results
object as a property of your view controller. From that point, you can use Realm's Change Notification feature to assign a Swift closure that'll be executed each time the Realm query changes. This can then be used to animate the updates on the collection view:
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()
}
}