【发布时间】:2021-11-30 03:52:56
【问题描述】:
我有一个带有自定义集合视图流布局的集合视图,该布局在某些部分后面添加了阴影。我收到了一位使用 iOS 13 的用户的崩溃报告,其中包含以下错误和堆栈跟踪:
Fatal Exception: NSInternalInconsistencyException
no UICollectionViewLayoutAttributes instance for -layoutAttributesForDecorationViewOfKind: shadowDecorationView at path <NSIndexPath: 0x96c5f0d4fd83d873> {length = 2, path = 4 - 0}
Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x12a794 __exceptionPreprocess
1 libobjc.A.dylib 0x5bcc objc_exception_throw
2 CoreFoundation 0x2d82c +[_CFXNotificationTokenRegistration keyCallbacks]
3 Foundation 0x8716c -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
4 UIKitCore 0x2a5d40 -[UICollectionViewData layoutAttributesForDecorationViewOfKind:atIndexPath:]
5 UIKitCore 0x2a32c4 -[UICollectionViewData rectForDecorationElementOfKind:atIndexPath:]
6 UIKitCore 0x283c50 -[UICollectionView _viewAnimationsForCurrentUpdate]
7 UIKitCore 0x287d1c __71-[UICollectionView _updateWithItems:tentativelyForReordering:animator:]_block_invoke.1887
8 UIKitCore 0xed51cc +[UIView(Animation) performWithoutAnimation:]
9 UIKitCore 0x286f48 -[UICollectionView _updateWithItems:tentativelyForReordering:animator:]
10 UIKitCore 0x2815b0 -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:]
11 UIKitCore 0x288eb0 -[UICollectionView _endUpdatesWithInvalidationContext:tentativelyForReordering:animator:]
12 UIKitCore 0x2891fc -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:animator:]
13 UIKitCore 0x289044 -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:]
14 UIKitCore 0x288fc8 -[UICollectionView _performBatchUpdates:completion:invalidationContext:]
15 UIKitCore 0x288f04 -[UICollectionView performBatchUpdates:completion:]
16 IGListKit 0x11c54 __67-[IGListAdapterUpdater performBatchUpdatesWithCollectionViewBlock:]_block_invoke.79 + 250 (IGListAdapterUpdater.m:250)
17 IGListKit 0x111d8 -[IGListAdapterUpdater performBatchUpdatesWithCollectionViewBlock:] + 272 (IGListAdapterUpdater.m:272)
18 IGListKit 0x12f78 __60-[IGListAdapterUpdater _queueUpdateWithCollectionViewBlock:]_block_invoke + 431 (IGListAdapterUpdater.m:431)
19 libdispatch.dylib 0x5a9a8 _dispatch_call_block_and_release
20 libdispatch.dylib 0x5b524 _dispatch_client_callout
21 libdispatch.dylib 0xd5b4 _dispatch_main_queue_callback_4CF$VARIANT$mp
22 CoreFoundation 0xa87fc __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
23 CoreFoundation 0xa36d0 __CFRunLoopRun
24 CoreFoundation 0xa2ce8 CFRunLoopRunSpecific
25 GraphicsServices 0x338c GSEventRunModal
26 UIKitCore 0xa2e444 UIApplicationMain
27 MyApp 0x4b2c main + 28 (MyModeLogic.swift:28)
28 libdyld.dylib 0x18f0 start
我的ShadowCollectionViewFlowLayout 看起来像这样:
protocol ShadowFlowLayoutDelegate: AnyObject {
func shouldDisplayShadowFor(section: Int) -> Bool
}
final class ShadowCollectionViewFlowLayout: UICollectionViewFlowLayout {
weak var decorationDelegate: ShadowFlowLayoutDelegate?
private let decorationViewKind = "shadowDecorationView"
override init() {
super.init()
register(ShadowReusableView.self, forDecorationViewOfKind: decorationViewKind)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
register(ShadowReusableView.self, forDecorationViewOfKind: decorationViewKind)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let parent = super.layoutAttributesForElements(in: rect)
guard
let attributes = parent,
!attributes.isEmpty else {
return parent
}
//attributes.forEach(configureRoundCornersAttributes)
// Display shadows for every section by default
var sectionsWithShadow = Set(attributes.map{$0.indexPath.section})
if let decorationDelegate = decorationDelegate {
// Ask decorationDelegate for sections with shadows, if it supports the protocol
sectionsWithShadow = sectionsWithShadow.filter{decorationDelegate.shouldDisplayShadowFor(section: $0)}
}
let backgroundShadowAttributes: [UICollectionViewLayoutAttributes] = sectionsWithShadow.compactMap{ section in
return layoutAttributesForDecorationView(
ofKind: decorationViewKind,
at: section
)
}
return attributes + backgroundShadowAttributes
}
private func layoutAttributesForDecorationView(ofKind elementKind: String, at section: Int) -> UICollectionViewLayoutAttributes? {
guard elementKind == decorationViewKind else {
return nil
}
guard let numberOfItems = collectionView?.numberOfItems(inSection: section) else {
return nil
}
let firstItemIndexPath = IndexPath(item: 0, section: section)
guard let firstItemFrame = layoutAttributesForItem(at: firstItemIndexPath)?.frame else {
return nil
}
let attributes = UICollectionViewLayoutAttributes(
forDecorationViewOfKind: elementKind,
with: firstItemIndexPath
)
let lastItemIndexPath = IndexPath(item: numberOfItems - 1, section: section)
guard let lastItemFrame = layoutAttributesForItem(at: lastItemIndexPath)?.frame else {
return nil
}
let heightDelta = lastItemFrame.maxY - firstItemFrame.minY
let frame = CGRect(
x: firstItemFrame.origin.x,
y: firstItemFrame.origin.y,
width: firstItemFrame.width,
height: heightDelta
)
attributes.frame = frame
attributes.zIndex = -1
return attributes
}
}
final class ShadowReusableView: UICollectionReusableView {
override func layoutSubviews() {
super.layoutSubviews()
backgroundColor = .neutral(.oneHundred)
layer.shadowOpacity = 0.3
layer.shadowColor = UIColor.neutral(.nineHundred).cgColor
layer.shadowRadius = 7
layer.cornerRadius = 15
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.masksToBounds = false
}
}
我将我的布局添加到情节提要中或像这样以编程方式:
let collectionView = UICollectionView(
frame: .zero,
collectionViewLayout: ShadowCollectionViewFlowLayout()
)
...
let layout = collectionView.collectionViewLayout as? ShadowCollectionViewFlowLayout
layout?.decorationDelegate = self
究竟是什么导致了崩溃,我该如何解决?
【问题讨论】:
标签: ios swift uicollectionview