所以,我使用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()也没有帮助。
有人用集合视图解决这个问题吗?
答案 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()
}
}