Я отправил это в Apple Feedback Assistant
Я использую UICollectionViewDiffableDataSourceReference
, и в первый и второй раз моя cellProvider
функция возвращает ячейку, кажется, все работают нормально.
Однако, как только объект обновляется, так что ячейка перезагружается, collectionView фактически не показывает ячейку, которую я предоставил в функции cellProvider
.
Я упустил что-то очевидное, или ошибка из-за l ie у меня в руках?
(проект с кодом также можно найти здесь: https://github.com/everlof/CollectionViewDequeuBug)
У меня есть простой объект основных данных, и при нажатии кнопки в подклассе UICollectionViewCell объект обновляется, и запускается перезагрузка этой ячейки.
Однако ячейка, которая была удалена и возвращена в cellProvider
не представлен в коллекции.
См .:
update(test:) -> <CollectionViewBug.MyCell: 0x7fd453e668c0; baseClass = UICollectionViewCell; frame = (10 10; 355 100); layer = <CALayer: 0x600002ce9ea0>>
Returning dequeued => <CollectionViewBug.MyCell: 0x7fd453e668c0; baseClass = UICollectionViewCell; frame = (10 10; 355 100); layer = <CALayer: 0x600002ce9ea0>>, test test.a => CE10C1C8-400A-47BF-BC7B-D13889A4B893
update(test:) -> <CollectionViewBug.MyCell: 0x7fd453e668c0; baseClass = UICollectionViewCell; frame = (10 10; 355 100); hidden = YES; layer = <CALayer: 0x600002ce9ea0>>
Returning dequeued => <CollectionViewBug.MyCell: 0x7fd453e668c0; baseClass = UICollectionViewCell; frame = (10 10; 355 100); hidden = YES; layer = <CALayer: 0x600002ce9ea0>>, test test.a => CE10C1C8-400A-47BF-BC7B-D13889A4B893
<trigger update by tapping button>
update(test:) -> <CollectionViewBug.MyCell: 0x7fd453e72ca0; baseClass = UICollectionViewCell; frame = (10 10; 355 100); layer = <CALayer: 0x600002cebd40>>
Returning dequeued => <CollectionViewBug.MyCell: 0x7fd453e72ca0; baseClass = UICollectionViewCell; frame = (10 10; 355 100); layer = <CALayer: 0x600002cebd40>>, test test.a => 7A2FC74B-22AB-4608-AF11-852A6191A8D6
Видите? Сначала я получаю ячейку 0x7fd453e668c0
, а затем, после запуска обновления, 0x7fd453e72ca0
отключается и возвращается, но не отображается!
Если я открою «Debug View Hierarchy», единственная ячейка внутри CollectionView
is: <CollectionViewBug.MyCell: 0x7fd453e668c0; baseClass = UICollectionViewCell; frame = (10 10; 355 100); layer = <CALayer: 0x600002ce9ea0>>
, которая фактически была первой ячейкой
Простой (CoreData) объект данных:
@objc(Test)
public class Test: NSManagedObject {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Test> {
return NSFetchRequest<Test>(entityName: "Test")
}
@NSManaged public var a: String?
@NSManaged public var b: String?
}
Моя ячейка в основном настолько мала, насколько я мог сделать это:
class MyCell: UICollectionViewCell {
static let identifier = "MyCell"
var test: Test?
let btn = UIButton()
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: .zero)
btn.setTitle("test", for: .normal)
btn.setTitleColor(.black, for: .normal)
btn.addTarget(self, action: #selector(doAction), for: .touchUpInside)
btn.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(label)
contentView.addSubview(btn)
contentView.backgroundColor = .white
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4).isActive = true
label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0).isActive = true
btn.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true
btn.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func doAction() {
// Set a new ID
let testID = test!.objectID
AppDelegate.persistentContainer.performBackgroundTask { ctx in
let test = ctx.object(with: testID) as! Test
test.a = UUID().uuidString
try! ctx.save()
}
}
func update(test: Test) {
self.test = test
print("update(test:) -> \(self)")
// Update cell's label with new ID
label.text = test.a
}
}
И, наконец, коллекция ViewView:
class CollectionView: UICollectionView, NSFetchedResultsControllerDelegate, UICollectionViewDelegate {
let fetchResultController: NSFetchedResultsController<Test>
var diffableDataSource: UICollectionViewDiffableDataSourceReference!
init() {
let fetchRequest: NSFetchRequest<Test> = Test.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Test.a, ascending: true)]
fetchResultController = NSFetchedResultsController<Test>(fetchRequest: fetchRequest,
managedObjectContext: AppDelegate.persistentContainer.viewContext,
sectionNameKeyPath: nil,
cacheName: nil)
let size = NSCollectionLayoutSize(widthDimension: NSCollectionLayoutDimension.fractionalWidth(1), heightDimension: NSCollectionLayoutDimension.estimated(100))
let item = NSCollectionLayoutItem(layoutSize: size)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitem: item, count: 1)
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
section.interGroupSpacing = 10
let layout = UICollectionViewCompositionalLayout(section: section)
super.init(frame: .zero, collectionViewLayout: layout)
register(MyCell.self, forCellWithReuseIdentifier: MyCell.identifier)
diffableDataSource =
UICollectionViewDiffableDataSourceReference(collectionView: self, cellProvider: { collectionView, indexPath, testID in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCell.identifier, for: indexPath) as! MyCell
let test = AppDelegate.persistentContainer.viewContext.object(with: testID as! NSManagedObjectID) as! Test
cell.update(test: test)
print("Returning dequeued => \(cell), test test.a => \(test.a!)")
return cell
}
)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func fetch() {
delegate = self
dataSource = diffableDataSource
fetchResultController.delegate = self
try? fetchResultController.performFetch()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
diffableDataSource.applySnapshot(snapshot, animatingDifferences: true)
}
}