我想在NSFetchedResultsControllerRelegate中使用CollectionViewController。因此,我只是更改了用于TableViewController的CollectionView方法。
(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.collectionView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]];
break;
case NSFetchedResultsChangeDelete:
[self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] ];
break;
}
}
(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UICollectionView *collectionView = self.collectionView;
switch(type) {
case NSFetchedResultsChangeInsert:
[collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]];
break;
case NSFetchedResultsChangeDelete:
[collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
break;
case NSFetchedResultsChangeUpdate:
[collectionView reloadItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
break;
case NSFetchedResultsChangeMove:
[collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
[collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]];
break;
}
}
(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.collectionView reloadData];
}但我不知道如何处理WillChangeContent (beginUpdates for TableView)和DidChangeContent (endUpdates for TableView)用于CollectionView。
一切正常,除非我将一个项目从一个部分移到另一个部分。然后我得到以下错误。
这通常是NSManagedObjectContextObjectsDidChangeNotification.观察者中的一个bug。无效更新:第0节中的无效项目数.
你知道我该怎么解决这个问题吗?
发布于 2013-12-12 21:31:05
将获取的结果控制器与集合视图组合起来有点棘手。这个问题在
如果您正在寻找如何使用
NSInternalInconsistencyException来绕过UICollectionView运行时异常,那么我有一个GitHub示例,详细介绍了如何从NSFetchedResultsControllerDelegate中排队更新。 问题是,现有的UITableView类使用beginUpdates和endUpdates向表视图提交批处理。UICollectionView有一个新的performBatchUpdates:方法,它接受一个块参数来更新集合视图。这很性感,但与现有的NSFetchedResultsController范式不太一样。
幸运的是,该文章还提供了一个示例实现:
来自自述机构:
这是一个如何将新的
UICollectionView与NSFetchedResultsController结合使用的示例。诀窍是将通过NSFetchedResultsControllerDelegate进行的更新排队,直到控制器完成其更新为止。UICollectionView的beginUpdates和endUpdates与UITableView必须让它轻松地与NSFetchedResultsController一起工作的beginUpdates和endUpdates不同,所以您必须对它们进行队列处理,否则就会得到内部一致性运行时异常。
发布于 2015-03-05 12:50:43
这是我在Swift中的实现。首先初始化一个NSBlockOperations数组:
var blockOperations: [NSBlockOperation] = []在控制器中,重新输入数组:
func controllerWillChangeContent(controller: NSFetchedResultsController) {
blockOperations.removeAll(keepCapacity: false)
}在“更改对象”方法中:
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
if type == NSFetchedResultsChangeType.Insert {
println("Insert Object: \(newIndexPath)")
blockOperations.append(
NSBlockOperation(block: { [weak self] in
if let this = self {
this.collectionView!.insertItemsAtIndexPaths([newIndexPath!])
}
})
)
}
else if type == NSFetchedResultsChangeType.Update {
println("Update Object: \(indexPath)")
blockOperations.append(
NSBlockOperation(block: { [weak self] in
if let this = self {
this.collectionView!.reloadItemsAtIndexPaths([indexPath!])
}
})
)
}
else if type == NSFetchedResultsChangeType.Move {
println("Move Object: \(indexPath)")
blockOperations.append(
NSBlockOperation(block: { [weak self] in
if let this = self {
this.collectionView!.moveItemAtIndexPath(indexPath!, toIndexPath: newIndexPath!)
}
})
)
}
else if type == NSFetchedResultsChangeType.Delete {
println("Delete Object: \(indexPath)")
blockOperations.append(
NSBlockOperation(block: { [weak self] in
if let this = self {
this.collectionView!.deleteItemsAtIndexPaths([indexPath!])
}
})
)
}
}在“更改节”方法中:
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
if type == NSFetchedResultsChangeType.Insert {
println("Insert Section: \(sectionIndex)")
blockOperations.append(
NSBlockOperation(block: { [weak self] in
if let this = self {
this.collectionView!.insertSections(NSIndexSet(index: sectionIndex))
}
})
)
}
else if type == NSFetchedResultsChangeType.Update {
println("Update Section: \(sectionIndex)")
blockOperations.append(
NSBlockOperation(block: { [weak self] in
if let this = self {
this.collectionView!.reloadSections(NSIndexSet(index: sectionIndex))
}
})
)
}
else if type == NSFetchedResultsChangeType.Delete {
println("Delete Section: \(sectionIndex)")
blockOperations.append(
NSBlockOperation(block: { [weak self] in
if let this = self {
this.collectionView!.deleteSections(NSIndexSet(index: sectionIndex))
}
})
)
}
}最后,在did控制器中确实更改了内容方法:
func controllerDidChangeContent(controller: NSFetchedResultsController) {
collectionView!.performBatchUpdates({ () -> Void in
for operation: NSBlockOperation in self.blockOperations {
operation.start()
}
}, completion: { (finished) -> Void in
self.blockOperations.removeAll(keepCapacity: false)
})
}我还亲自在deinit方法中添加了一些代码,以便在ViewController即将被解除分配时取消操作:
deinit {
// Cancel all block operations when VC deallocates
for operation: NSBlockOperation in blockOperations {
operation.cancel()
}
blockOperations.removeAll(keepCapacity: false)
}发布于 2016-01-09 14:37:43
我制作了@ and的解决方案 it's 自有对象并将其转换为Swift 2
import Foundation
import CoreData
class CollectionViewFetchedResultsControllerDelegate: NSObject, NSFetchedResultsControllerDelegate {
// MARK: Properties
private let collectionView: UICollectionView
private var blockOperations: [NSBlockOperation] = []
// MARK: Init
init(collectionView: UICollectionView) {
self.collectionView = collectionView
}
// MARK: Deinit
deinit {
blockOperations.forEach { $0.cancel() }
blockOperations.removeAll(keepCapacity: false)
}
// MARK: NSFetchedResultsControllerDelegate
func controllerWillChangeContent(controller: NSFetchedResultsController) {
blockOperations.removeAll(keepCapacity: false)
}
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case .Insert:
guard let newIndexPath = newIndexPath else { return }
let op = NSBlockOperation { [weak self] in self?.collectionView.insertItemsAtIndexPaths([newIndexPath]) }
blockOperations.append(op)
case .Update:
guard let newIndexPath = newIndexPath else { return }
let op = NSBlockOperation { [weak self] in self?.collectionView.reloadItemsAtIndexPaths([newIndexPath]) }
blockOperations.append(op)
case .Move:
guard let indexPath = indexPath else { return }
guard let newIndexPath = newIndexPath else { return }
let op = NSBlockOperation { [weak self] in self?.collectionView.moveItemAtIndexPath(indexPath, toIndexPath: newIndexPath) }
blockOperations.append(op)
case .Delete:
guard let indexPath = indexPath else { return }
let op = NSBlockOperation { [weak self] in self?.collectionView.deleteItemsAtIndexPaths([indexPath]) }
blockOperations.append(op)
}
}
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
switch type {
case .Insert:
let op = NSBlockOperation { [weak self] in self?.collectionView.insertSections(NSIndexSet(index: sectionIndex)) }
blockOperations.append(op)
case .Update:
let op = NSBlockOperation { [weak self] in self?.collectionView.reloadSections(NSIndexSet(index: sectionIndex)) }
blockOperations.append(op)
case .Delete:
let op = NSBlockOperation { [weak self] in self?.collectionView.deleteSections(NSIndexSet(index: sectionIndex)) }
blockOperations.append(op)
default: break
}
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
collectionView.performBatchUpdates({
self.blockOperations.forEach { $0.start() }
}, completion: { finished in
self.blockOperations.removeAll(keepCapacity: false)
})
}
}用法:
fetchedResultsController.delegate = CollectionViewFetchedResultsControllerDelegate(collectionView)Swift 4版
private var blockOperations: [BlockOperation] = []
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
blockOperations.removeAll(keepingCapacity: false)
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange anObject: Any,
at indexPath: IndexPath?,
for type: NSFetchedResultsChangeType,
newIndexPath: IndexPath?) {
let op: BlockOperation
switch type {
case .insert:
guard let newIndexPath = newIndexPath else { return }
op = BlockOperation { self.collectionView.insertItems(at: [newIndexPath]) }
case .delete:
guard let indexPath = indexPath else { return }
op = BlockOperation { self.collectionView.deleteItems(at: [indexPath]) }
case .move:
guard let indexPath = indexPath, let newIndexPath = newIndexPath else { return }
op = BlockOperation { self.collectionView.moveItem(at: indexPath, to: newIndexPath) }
case .update:
guard let indexPath = indexPath else { return }
op = BlockOperation { self.collectionView.reloadItems(at: [indexPath]) }
}
blockOperations.append(op)
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
collectionView.performBatchUpdates({
self.blockOperations.forEach { $0.start() }
}, completion: { finished in
self.blockOperations.removeAll(keepingCapacity: false)
})
}https://stackoverflow.com/questions/20554137
复制相似问题