I get this error when I try to update my collectionView layout on iOS 14: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSDictionaryM setObject:forKey:]: object cannot be nil (key: <NSIndexPath: 0x9f9aa264ee754972> {length = 2, path = 0 - 0})'
However it works absolutely fine on iOS 16! Even on another view controller it works fine with iOS 14.
collectionView.setCollectionViewLayout(mode.layout, animated: false)
extension ItemsViewMode {
var layout: UICollectionViewFlowLayout {
switch self {
case .card:
return OfferingCardLayout()
case .investmentCard:
return InvestmentsCardLayout()
case .list:
return OfferingListLayout()
case .investmentList:
return InvestmentsListLayout()
}
}
}
class InvestmentsListLayout: OfferingListLayout {
private enum Const {
static let itemHeight: CGFloat = 164
static let minimumLineSpacing: CGFloat = 16
}
override init() {
super.init()
itemHeight = Const.itemHeight
minimumLineSpacing = Const.minimumLineSpacing
}
}
class OfferingListLayout: UICollectionViewFlowLayout {
private enum Const {
static let minimumInteritemSpacing: CGFloat = 0
static let minimumLineSpacing: CGFloat = 2
static let leftRightSpacing: CGFloat = 8
static let itemHeight: CGFloat = 216
}
var itemHeight: CGFloat = Const.itemHeight
override init() {
super.init()
register(SeparatorView.self, forDecorationViewOfKind: "separator")
scrollDirection = .vertical
minimumInteritemSpacing = Const.minimumInteritemSpacing
minimumLineSpacing = Const.minimumLineSpacing
footerReferenceSize = CGSize(width: 50, height: 50)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
guard let collectionView = collectionView, collectionView.numberOfSections > 0 else { return }
itemSize = CGSize(width: collectionView.frame.width - Const.leftRightSpacing * 2, height: itemHeight)
super.prepare()
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
true
}
override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext {
guard let context = super.invalidationContext(forBoundsChange: newBounds) as? UICollectionViewFlowLayoutInvalidationContext else {
return UICollectionViewLayoutInvalidationContext()
}
context.invalidateFlowLayoutDelegateMetrics = newBounds.size != collectionView?.bounds.size
return context
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes] {
let layoutAttributes = super.layoutAttributesForElements(in: rect) ?? []
let lineWidth: CGFloat = Const.minimumLineSpacing
var decorationAttributes: [UICollectionViewLayoutAttributes] = []
// skip first cell
for layoutAttribute in layoutAttributes where layoutAttribute.indexPath.item > 0 {
let separatorAttribute = UICollectionViewLayoutAttributes(forDecorationViewOfKind: "separator", with: layoutAttribute.indexPath)
let cellFrame = layoutAttribute.frame
separatorAttribute.frame = CGRect(x: cellFrame.origin.x, y: cellFrame.origin.y - lineWidth, width: cellFrame.size.width, height: lineWidth)
separatorAttribute.zIndex = Int.max
decorationAttributes.append(separatorAttribute)
}
return layoutAttributes + decorationAttributes
}
}
I even tried setting breakpoints here but no luck.
I implemented the following function in my layout class and it works fine now: