I have an issue where [unowned self] was changed to [weak self] within the dataSource function used for a CollectionView using RxDataSource due to a memory leak. I now received a crash from returning a blank collectionViewCell that doesn't have a reuseIdentifier. I understand that I need to return a cell with a reuseID.
What changes are suggested to deal with this properly?
Someone suggested making collectionView.dataSource = nil in viewDidLoad() would fix this...
I was thinking instead of returning CanvasItemCollectionViewCell() in the 'guard' check, I return collectionView.dequeueReusableCell(for: indexPath, cellType: CanvasItemCollectionViewCell.self), but if self = self fails wouldn't that mean the collectionView is garbage?
This is a difficult problem to debug because this crash doesn't happen consistently.
Here are some screenshots to portray what I am looking at.
func dataSource()
-> RxCollectionViewSectionedAnimatedDataSource<CanvasSectionModel> {
RxCollectionViewSectionedAnimatedDataSource<CanvasSectionModel>(
animationConfiguration: AnimationConfiguration(
insertAnimation: .fade,
reloadAnimation: .fade,
deleteAnimation: .fade
),
configureCell: { [weak self] dataSource, collectionView, indexPath, _ in
guard let self = self else { return CanvasItemCollectionViewCell() }
switch dataSource[indexPath] {
case let .CellModel(model):
let cell = collectionView
.dequeueReusableCell(
for: indexPath,
cellType: CanvasItemCollectionViewCell.self
)
cell.model = model
cell.onDeleteHandler = { _ in
self.presentDeleteConfirmation { deleteConfirmed in
guard deleteConfirmed else { return }
self.viewModel.inputs.deletePage(withProofID: model.id)
}
}
return cell
}
}
Ultimately, the problem is here:
cell.onDeleteHandler = { _ in
self.presentDeleteConfirmation { deleteConfirmed in
guard deleteConfirmed else { return }
self.viewModel.inputs.deletePage(withProofID: model.id)
}
}
Don't use self
and you won't have a problem with self references so you won't need to import a weak self and then worry about the guard let self...
self
reference, replace it with UIViewController.top()
(see below for implementation.)self
reference, capture viewModel
instead.extension UIViewController {
static func top() -> UIViewController {
guard let rootViewController = UIApplication.shared.delegate?.window??.rootViewController else { fatalError("No view controller present in app?") }
var result = rootViewController
while let vc = result.presentedViewController, !vc.isBeingDismissed {
result = vc
}
return result
}
}