我已经实现了这样的 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()
如果然后从 UIViewControllerRepresentable 中的 updateUIViewController 再次调用此方法,则集合视图为空。
这是此示例 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)
显示单元格。但是在点击手势上强制执行的连续刷新会挂起 UI(我认为可能有太多的项目并且计算动画有问题,但即使我将项目数量减少到 1000 它也不会冻结。)
更新 2
现在当动画:在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”而终止应用程序,原因:“无法使同类视图出列:带有标识符 ItemCell 的 UICollectionElementKindCell - 必须为标识符注册 nib 或类或连接故事板中的原型单元格 *** 第一次抛出调用堆栈:( 0 CoreFoundation 0x00007fff23e39f0e exceptionPreprocess + 350 1 libobjc.A.dylib
0x00007fff50ad79b2 objc_exception_throw + 48 2 CoreFoundation
0x00007fff23e39c88 +[NSException raise:format:arguments:] + 88 3
Foundation 0x00007fff258a3cd2 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 191 4
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:notify:] + 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:animator:]_block_invoke.1887 + 118 20 UIKitCore 0x00007fff490bb8a8 +[UIView(Animation) performWithoutAnimation:] + 84 21 UIKitCore 0x00007fff48398b24 - [UICollectionView _updateWithItems:tentativelyForReordering:animator:] + 4003 22 UIKitCore 0x00007fff48391689 -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:] + 16761 23 UIKitCore 0x00007fff4839b0e6-[UICollectionContext:tentativelyForReorderWithInvalidation:]animator:] + 71 24 UIKitCore 0x00007fff4839b445 -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:animator:] + 462 25 UIKitCore 0x00007fff4839b254 -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:] + 90 26 UIKitCore 0x00007fff4839b1d7 -[UICollectionView _performBatchUpdates:completion :invalidationContext:] + 74 27 UIKitCore 0x00007fff4839b12c -[UICollectionView performBatchUpdates:completion:] + 53 28 UIKitCore 0x00007fff483aa9ef -[UICollectionView _performDiffableUpdate:] + 44 29 UIKitCore 0x00007fff4834906e -[_UIDiffableDataSourceViewUpdater _performUpdateWithCollectionViewUpdateItems:dataSourceSnapshotter:updateHandler:completion:] + 467 30 UIKitCore 0x00007fff4834213a -[__UIDiffableDataSource _commitNewDataSource:withViewUpdates:completion:] + 246 31 UIKitCore 0x00007fff4833cb22 __66-[__UIDiffableDataSource applyDifferencesFromSnapshot:completion:]_block_invoke.154 + 190 32 UIKitCore 0x00007fff4833cdb1 __66-[__UIDiffableDataSource applyDifferencesFromSnapshot:completion:]_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:completion:] + 952 36 UIKitCore 0x00007fff4833d63d -[__UIDiffableDataSource applyDifferencesFromSnapshot:animatingDifferences:completion:] + 71 37 libswiftUIKit.dylib 0x00007fff5170aaf4 $s5UIKit34UICollectionViewDiffableDataSourceC5apply_20animatingDifferences10completionyAA010NSDiffableeF8SnapshotVyxq_G_SbyycSgtFTm + 212 38 SwiftUICollectionView 0x0000000108b620b9 $s21SwiftUICollectionView010CollectionC10ControllerC16reloadDataSource8snapshot9animatingy5UIKit010NSDiffablegH8SnapshotVyAA7SectionOAA4ItemCG_SbtF + 985 39 SwiftUICollectionView 0x0000000108b5682f $s21SwiftUICollectionView010CollectionC0V22updateUIViewController_7contextyAA0dcG0C_0A2UI0fG20RepresentableContextVyACGtF + 335 40 SwiftUICollectionView 0x0000000108b56a2b $s21SwiftUICollectionView010CollectionC0V0A2UI29UIViewControllerRepresentableAadEP06updatefG0_7contexty0fG4TypeQz_AD0fgH7ContextVyxGtFTW + 59 41 SwiftUI0x00007fff2c59a1b2 $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 51AttributeGraph 0x00007fff2fc33d5b _ZN2AG8Subgraph6updateEj + 729 52 SwiftUI 0x00007fff2c51d690 $s7SwiftUI9ViewGraphC14runTransaction33_D63C4EB7F2B205694B6515509E76E98BLL2inySo10AGGraphRefa_tF + 224 53 SwiftUI 0x00007fff2c51da67 $s7SwiftUI9ViewGraphC13updateOutputs2atyAA4TimeV_tFSb5prefs_Sb9idealSizeAC0F0V7outputstSo10AGGraphRefaXEfU_ + 103 54 SwiftUI 0x00007fff2c51d74d $s7SwiftUI9ViewGraphC13updateOutputs2atyAA4TimeV_tF + 125 55 SwiftUI 0x00007fff2c80146b $s7SwiftUI16ViewRendererHostPAAE6render8interval17updateDisplayListySd_SbtFyyXEfU_yyXEfU_ + 811 56 SwiftUI 0x00007fff2c8008c3 $s7SwiftUI16ViewRendererHostPAAE6render8interval17updateDisplayListySd_SbtFyyXEfU_ + 547 57SwiftUI 0x00007fff2c7f6415 $s7SwiftUI16ViewRendererHostPAAE6render8interval17updateDisplayListySd_SbtF + 373 58 SwiftUI 0x00007fff2c956102 $s7SwiftUI14_UIHostingViewC14layoutSubviewsyyF + 226 59 SwiftUI
0x00007fff2c956125 $s7SwiftUI14_UIHostingViewC14layoutSubviewsyyFTo + 21 60 UIKitCore 0x00007fff490c9848 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2478 61 QuartzCore 0x00007fff2b4ae3f0 -[CALayer]2 QuartlayerzCore layout+25566
0x00007fff2b4b457b _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 523 63 QuartzCore 0x00007fff2b4bfc12 _ZN2CA5Layer28layout_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 0x00007fff23d9dcdc __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK+ 12 68 CoreFoundation 0x00007fff23d9d3d3 __CFRunLoopDoBlocks + 195 69 CoreFoundation 0x00007fff23d981c3 __CFRunLoopRun + 995 70 CoreFoundation
0x00007fff23d97ac4 CFRunLoopRunSpecific + 404 71 GraphicsServices
0x00007fff38b2fc1a GSEventRunModal + 139 72 UIKitCore
0x00007fff48bc7f80 UIApplicationMain + 1605 73 SwiftUICollectionView 0x0000000108b548fb main + 75 74 libdyld.dylib
0x00007fff519521fd start + 1 )
我忘了说当我用简单的 UICollectionFlowLayout 替换 CompositionalLayout 时,这个异常开始发生了!