Оболочка SwiftUI CollectionView не может применить снимок из updateUIViewController - PullRequest
0 голосов
/ 01 мая 2020

Я реализовал такую ​​оболочку UICollectionView

struct CollectionView: UIViewControllerRepresentable {

    // MARK: - Properties
    let layout: UICollectionViewLayout
    let sections: [Section]
    let items: [Section: [Item]]

    // MARK: - Actions
    let content: (_ indexPath: IndexPath, _ item: Item) -> AnyView

    init(layout: UICollectionViewLayout,
         sections: [Section],
         items: [Section: [Item]],
         @ViewBuilder content:  @escaping (_ indexPath: IndexPath, _ item: Item) -> AnyView) {
        self.layout = layout

        self.sections = sections
        self.items = items

        self.content = content
    }

    func makeUIViewController(context: Context) -> CollectionViewController {

        let controller = CollectionViewController()
        controller.layout = layout
        controller.content = content
        controller.snapshot = snapshotForCurrentState()

        controller.collectionView.delegate = context.coordinator

        return controller
    }

    func updateUIViewController(_ controller: CollectionViewController, context: Context) {

        controller.snapshot = snapshotForCurrentState()
        controller.reloadDataSource()
    }


    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
}

А вот код CollectionViewController

class CollectionViewController: UIViewController {

    var layout: UICollectionViewLayout! = nil
    var snapshot: NSDiffableDataSourceSnapshot<Section, Item>! = nil
    var content: ((_ indexPath: IndexPath, _ item: Item) -> AnyView)! = nil

    let queue = DispatchQueue(label: "diffQueue")

    lazy var dataSource: UICollectionViewDiffableDataSource<Section, Item> = {
        let dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: cellProvider)
        return dataSource
    }()

    lazy var collectionView: UICollectionView = {
        let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
        collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        collectionView.backgroundColor = .red //.clear
        return collectionView
    }()

    var isLoaded: Bool = false

    override func viewDidLoad() {
        super.viewDidLoad()

        configureCollectionView()

        // load initial data
        reloadDataSource()

        isLoaded = true
    }
}

extension CollectionViewController {

    func reloadDataSource(animating: Bool = false) {

        dataSource.apply(snapshot, animatingDifferences: animating) {
            print("applying snapshot completed!")
        }
    }
}

extension CollectionViewController {

    private func configureCollectionView() {
        view.addSubview(collectionView)

        collectionView.register(HostingControllerCollectionViewCell<AnyView>.self, forCellWithReuseIdentifier: HostingControllerCollectionViewCell<AnyView>.reuseIdentifier)

        collectionView.delegate = self

        print("configured collection view")
    }

    private func cellProvider(collectionView: UICollectionView, indexPath: IndexPath, item: Item) -> UICollectionViewCell? {

        print("providing cell for \(indexPath)...")
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: HostingControllerCollectionViewCell<AnyView>.reuseIdentifier, for: indexPath) as? HostingControllerCollectionViewCell<AnyView> else {
            fatalError("Could not load cell")
        }

        //cell.host(AnyView(Text(item.title)))
        cell.host(content(indexPath, item))

        return cell
    }
}

Это работает, но я могу только загрузить источник данных в viewDidLoad, вызывая reloadDatasource(), если это метод вызывается снова из updateUIViewController в UIViewControllerRepresentable, после чего представление коллекции остается пустым.

Вот полный репозиторий этого образца. Оболочка CollectionView https://github.com/michzio/SwifUICollectionView

ОБНОВЛЕНИЕ

Я заметил, что я получая эту ошибку

2020-05-02 07:18:20.891685+0200 SwiftUICollectionView[39727:58991470] [CollectionView] Layout attributes <UICollectionViewLayoutAttributes: 0x7fbd6f30b270> index path: (<NSIndexPath: 0xd64d621a2e1d9027> {length = 2, path = 0 - 37}); frame = (187.667 792; 187.667 44);  were received from the layout <UICollectionViewCompositionalLayout: 0x7fbd6df04920> but are not valid for the data source counts. Attributes will be ignored.

Я также заметил, что если я изменю в updateUIViewController

controller.reloadDataSource(animating: false)

на

controller.reloadDataSource(animating: true)

ячейка отображаются. Но последовательный refre sh, примененный к жесту касания, приводит к зависанию пользовательского интерфейса (я думаю, что, возможно, слишком много элементов, и при вычислении анимации возникают проблемы, но нет, даже если я уменьшил количество элементов до 1000, он зависает).

ОБНОВЛЕНИЕ 2

Теперь при анимации: true в reloadDataSource () (из updateUIViewController) я могу получить сбои, но нет информации только EXC_BAD_ARITHM

, если я удаляю начальную загрузку данных в CollectionViewController.viewDidLoad () только тогда вызывается updateUIViewController, и здесь происходит еще одно странное исключение

* Ошибка подтверждения в - [UICollectionView _dequeueReusableViewOfKind: withIdentifier: forIndexPath: viewCategory:], /Library/Caches/com.apple.xbs/Sources /UIKitCore_Sim/UIKit-3920.26.113/UICollectionView.m:5971 2020-05-02 07: 33: 02.037804 + 0200 SwiftUICollectionView [40091: 59004149] * Завершение работы приложения из-за невыполненного исключения «NSInternalInconsistencyException», причина: «может не исключать вид из вида: UICollectionEle mentKindCell с идентификатором ItemCell - должен зарегистрировать перо или класс для идентификатора или подключить ячейку прототипа в раскадровке '*** Первый вызов вызова: (0 CoreFoundation 0x00007fff23e39f0e exceptionPreprocess + 350 1 libobj c .A. dylib
0x00007fff50ad79b2 objc_exception_throw + 48 2 CoreFoundation
0x00007fff23e39c88 + [Повышение NSException: формат: аргументы:] + 88 3
Foundation 0x00007fff258a3cd2 - дескриптор объекта: 4: NSH: 1043 * UIKitCore 0x00007fff4838b36e - [UICollectionView _dequeueReusableViewOfKind: withIdentifier: forIndexPath: viewCategory:] + 2426 5 UIKitCore 0x00007fff4838b53d - [UICollectionView dequeueReusableCellWithReuseIdentifier: forIndexPath:] + 88 6
SwiftUICollectionView 0x0000000108b5fcb3 $ s21SwiftUICollectionView010CollectionC10ControllerC12cellProvider33_7499D878310ABE7B5F37FEF32561A438LL010collectionC09indexPath4itemSo0bC4CellCSgSo0bC0C_10Foundation05IndexP0VAA4ItemCtF + 867 7 SwiftUICollectionView 0x0000000108b62ad0 $ s21SwiftUICollectionView010CollectionC10ControllerC12cellProvider33_7499D878310ABE7B5F37FEF32561A438LL010collectionC09indexPath4itemSo0bC4CellCSgSo0bC0C_10Foundation05IndexP0VAA4ItemCtFTA + 16 8 SwiftUICollectionView 0x0000000108b5ffaf $ sSo16UICollectionViewC10Foundation9IndexPathV05SwiftaB04ItemCSo0aB4CellCSgIeggngo_AbehKIeggnno_TR + 15 9 libswiftUIKit.dylib 0x00007fff5170a8ce $ s5UIKit29UITableViewDiffableDataSourceC05tableC012cellProviderACyxq_GSo0bC0C_So0bC4CellCSgAH_10Foundation9IndexPathVq_tctcfcAkH_ANyptcfU_ + 126 10 libswiftUIKit.dylib 0x00007fff5170a998 $ sSo11UITableViewC10Foundation9IndexPathVypSo0aB4CellCSgIeggnno_ABSo07NSIndexE0CyXlAHIeyByyya_TR + 168 11 UIKitCore 0x00007fff48342a89 - [__ UIDiffableDataSource CollectionView: cellForItemAtIndexPath:] + 165 12 UIKitCore 0x00007fff483432d5 - [ __UIDiffableDataSource _cellForItemAtIndexPath: collectionView:] + 50 13 libswiftUIKit.dylib 0x00007fff5170b036 $ S5UIKit34UICollectionViewDiffableDataSourceC010collectionC0_13cellForItemAtSo0bC4CellCSo0bC0C_10Foundation9IndexPathVtFTm + 70 14 libswiftUIKit.dylib 0x00007fff5170b110 $ s5UIKit34UICollectionViewDiffableDataSourceC010collectionC0_13cellForItemAtSo0bC4CellCSo0bC0C_10Foundation9IndexPathVtFToTm + 128 15 UIKitCore 0x00007fff483759d5 - [UICollectionView _createPreparedCellForItemAtIndexPath: withLayoutAttributes: applyAttributes: IsFocused: уведомить:] + 416 16 UIKitCore 0x00007fff4837582f - [UICollectionView _createPreparedCellForItemAtIndexPath: withLayoutAttributes: applyAttributes:] + 31 17 UIKitCore 0x00007fff48395e4e __51- [UICollectionView _viewAnimationsForCurrentUpdate] _block_invoke.1814 + 661 18 UIKitCore 0x00007fff483929e4 - [UICollectionView _viewAnimationsForCurrentUpdate] + 3213 19 UIKitCore 0x00007fff48399cde __71- [UICollectionView _updateWithItems: tentativelyForReordering: аниматора:] _ block_invoke.1887 + 118 20 UIKitCore 0x00007fff490bb8a8 + [UIView (анимация) performWithoutAnimation :] + 84 21 UIKitCore 0x00007fff48398b24 - [UICollectionView _updateWithItems: tentativelyForReordering: аниматора:] + 4003 22 UIKitCore 0x00007fff48391689 - [UICollectionView _endItemAnimationsWithInvalidationContext: tentativelyForReordering: аниматора:] + 16761 23 UIKitCore 0x00007fff4839b0e6 - [UICollectionView _endUpdatesWithInvalidationContext: tentativelyForReordering: аниматора:] + 71 24 UIKitCore 0x00007fff4839b445 - [UICollectionView _performBatchUpdates: завершение: invalidationContext: tentativelyForReordering: аниматор:] + 462 25 UIKitCore 0x00007fff4839b254 - [UICollectionView _performBatchUpdates: завершение: invalidationContext: tentativelyForReordering:] + 90 26 UIKitCore 0x00007fff4839b1d7 - [UICollectionView _performBatchUpdates: завершение: invalidationContext:] + 74 27 UIKitCore 0x00007fff4839b12c - [UICollectionView executeBatchUpdates: завершение:] + 53 28 UIKitCore 0x00007fff483aa9ef - [UICollectionView _performDiffableUpdate:] + 44 29 UIKitCore 0x00007fff4834906e - [_ UIDiffableDataSourceViewUpd Ater _performUpdateWithCollectionViewUpdateItems: dataSourceSnapshotter: updateHandler: завершение:] + 467 30 UIKitCore 0x00007fff4834213a - [__ UIDiffableDataSource _commitNewDataSource: withViewUpdates: завершение:] + 246 31 UIKitCore 0x00007fff4833cb22 __66 - [__ UIDiffableDataSource applyDifferencesFromSnapshot: завершение:] _ block_invoke.154 + 190 32 UIKitCore 0x00007fff4833cdb1 __66- [ __UIDiffableDataSource applyDifferencesFromSnapshot: завершение:] _ block_invoke.180 + 107 33 libdispatch.dylib 0x0000000108e01e8e _dispatch_client_callout + 8 34 libdispatch.dylib 0x0000000108e10ae2 _dispatch_lane_barrier_sync_invoke_and_complete + 132 35 UIKitCore 0x00007fff4833c62b - [__ UIDiffableDataSource applyDifferencesFromSnapshot: завершение:] + 952 36 UIKitCore 0x00007fff4833d63d - [__ UIDiffableDataSource applyDifferencesFromSnapshot: animatingDifferences: завершение:] + 71 37 libswiftUIKit.dylib 0x00007fff5170aaf4 $ s5UIKit34UICollectionViewDiffableDataSourceC5apply_20animatingDifferences10completionyAA010NSDi ffableeF8SnapshotVyxq_G_SbyycSgtFTm + 212 38 SwiftUICollectionView 0x0000000108b620b9 $ s21SwiftUICollectionView010CollectionC10КонтроллерC16reloadDataSource8snapshot9animatingy5DNaTeAНоСоБВ7ПодключениеВыбезиБлокирование 0 + 985 39 SwiftUICollectionView 0x0000000108b5682f $ s21SwiftUICollectionView010CollectionC0V22updateUIViewController_7contextyAA0dcG0C_0A2UI0fG20RepresentableContextVyACGtF + 335 40 SwiftUICollectionView 0x0000000108b56a2b $ s21SwiftUICollectionView010CollectionC0V0A2UI29UIViewControllerRepresentableAadEP06updatefG0_7contexty0fG4TypeQz_AD0fgH7ContextVyxGtFTW + 59 41 SwiftUI 0x00007fff2c59a1b2 $ s7SwiftUI42PlatformViewControllerRepresentableAdaptorV06updateD8Provider_7contexty06UIViewE4TypeQz_AA0cdF7ContextVyACyxGGtF + 290 42 SwiftUI 0x00007fff2c670439 $ s7SwiftUI17PlatformViewChild33_A513612C07DFA438E70B9FA90719B40DLLV6update7contexty14AttributeGraph0O7ContextVyADyxGGz_tFyyXEfU_yyXEfU_ + 217 43 SwiftUI 0x00007fff2c7f5e20 $ s7SwiftUI16ViewRendererHostPAAE21performExternalUpdateyyyyXEF + 192 44 SwiftUI 0x00007fff2c66f810 $ s7SwiftUI17PlatformViewChild33_A513612C07DFA438E70B9FA90719B40DLLV6update7contexty14AttributeGraph0O7ContextVyADyxGGz_tFyyXEfU_7performL_4workyyyXE_tAA0cD13RepresentableRzlF + 224 45 SwiftUI 0x00007fff2c66e6b6 $ s7SwiftUI17PlatformViewChild33_A513612C07DFA438E70B9FA90719B40DLLV6update7contexty14AttributeGraph0O7ContextVyADyxGGz_tFyyXEfU_ + 2454 46 SwiftUI 0x00007fff2c6674ae $ s7SwiftUI17PlatformViewChild33_A513612C07DFA438E70B9FA90719B40DLLV6update7contexty14AttributeGraph0O7ContextVyADyxGGz_tF + 590 47 SwiftUI 0x00007fff2c670940 $ s7SwiftUI17PlatformViewChild33_A513612C07DFA438E70B9FA90719B40DLLVyxG14AttributeGraph07UntypedM0AafGP7_update_5graph9attributeySv_So10AGGraphRefaSo11AGAttributeatFZTW + 32 48 AttributeGraph 0x00007fff2fc46309 $ STA + 25 49 AttributeGraph 0x00007fff2fc2ed45 _ZN2AG5Graph11UpdateStack6updateEv + 455 50 AttributeGraph 0x00007fff2fc2f253 _ZN2AG5Graph16update_attributeEjb + 373 51 AttributeGraph 0x00007fff2fc33d5b _ZN2AG8Subgraph6updateEj + 729 52 SwiftUI 0x00007fff2c51d690 $ s7SwiftUI9ViewGraphC14runTransaction33_D63C4EB7F2B205694B6515509E76E98BLL2inySo10AGGraphRefa_tF + 224 53 SwiftUI 0x00007fff2c51da13UupTupSuDWS7 uts2atyAA4TimeV_tFSb5prefs_Sb9idealSizeAC0F0V7outputstSo10AGGraphRefaXEfU_ + 103 54 SwiftUI 0x00007fff2c51d74d $ s7SwiftUI9ViewGraphC13updateOutputs2atyAA4TimeV_tF + 125 55 SwiftUI 0x00007fff2c80146b $ s7SwiftUI16ViewRendererHostPAAE6render8interval17updateDisplayListySd_SbtFyyXEfU_yyXEfU_ + 811 56 SwiftUI 0x00007fff2c8008c3 $ s7SwiftUI16ViewRendererHostPAAE6render8interval17updateDisplayListySd_SbtFyyXEfU_ + 547 57 SwiftUI 0x00007fff2c7f6415 $ s7SwiftUI16ViewRendererHostPAAE6render8interval17updateDisplayListySd_SbtF + 373 58 SwiftUI 0x00007fff2c956102 $ s7SwiftUI14_UIHostingViewC14layoutSubviewsyyF + 226 59 SwiftUI * 1 045 * 0x00007fff2c956125 $ s7SwiftUI14_UIHostingViewC14layoutSubviewsyyFTo + 21 60 UIKitCore 0x00007fff490c9848 - [UIView (CALayerDelegate) layoutSublayersOfLayer:] + 2478 61 QuartzCore 0x00007fff2b4ae3f0 - [CALayer layoutSublayers] + 255 62 QuartzCore
0x00007fff2b4b457b _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 523 63 QuartzCore 0x00007fff2b4bfc12 _ZN2CA5Layer28lay out_and_display_if_neededEPNS_11TransactionE + 80 64 QuartzCore 0x00007fff2b408c84 _ZN2CA7Context18commit_transactionEPNS_11TransactionEd + 324 65 QuartzCore 0x00007fff2b43c65f _ZN2CA11Transaction6commitEv + 649 66 UIKitCore 0x00007fff48bdfc2b __34- [UIApplication _firstCommitBlock] _block_invoke_2 + 81 67 CoreFoundation 0x00007fff23d9dcd * * __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK тысяча пятьдесят-восемь
12 + 68 CoreFoundation 0x00007fff23d9d3d3 __CFRunLoopDoBlocks + 195 69 CoreFoundation 0x00007fff23d981c3 __CFRunLoopRun + 995 70 CoreFoundation
0x00007fff23d97ac4 CFRunLoopRunSpecifi c + 404 71 GraphicsServices * * 0x00007fff38b2fc1a тысяча сорок-девять GSEventRunModal + 139 72 UIKitCore
0x00007fff48bc7f80 UIApplicationMain + 1605 73 SwiftUICollectionView 0x0000000108b548fb основной + 75 74 libdyld.dylib * * 0x00007fff519521fd тысяча пятьдесят один старт + 1)

Я забыл сказать что эти исключения начинают происходить, когда я заменяю CompositionalLayout на простой UICollectionFlowLayout!

1 Ответ

0 голосов
/ 01 мая 2020

Как я вижу, вы не применяете новый снимок в методе updateUIViewController. Это должно быть что-то вроде этого

func updateUIViewController(_ controller: CollectionViewController, context: Context) {

    controller.snapshot = snapshotForCurrentState()
    controller.reloadDataSource()
}
...