Возврат ячейки в'cellProvider` не отображается в UICollectionView - PullRequest
0 голосов
/ 19 января 2020

Я отправил это в 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)
    }

}
...