Hi I’ve HomeCollectionViewCellComponent which is using in HomeCollectionViewCell and also there is a struct that holds size calculation logics for my collectionView (HomeCollectionViewCellSizeCalculator). it is calling in sizeForItem method of UICollectionViewDelegateFlowLayout. I hide my imageView when kingfisher is failed to downloading but I also want to compute imageSize as zero. I should tell to sizeCalculator from the setData function inside the HomeCollectionViewCellComponent. I used NotificationCenter but its objc method does not called.
HomeCollectionViewCellComponent setData func
func setData(with data: Article?) {
guard let data = data else { return }
if let imageUrl = data.urlToImage, let url = URL(string: imageUrl) {
self.newsImageView.kf.setImage(with: url) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(_):
break
case .failure(_):
self.newsImageView.isHidden = true
NotificationCenter.default.post(name: .kingfisherFail, object: nil)
}
}
}
}
HomeCollectionViewCellSizeCalculator
class HomeCollectionViewCellSizeCalculator {
private let width: CGFloat
private let article: Article?
private var imageDownloadingFailed: Bool = false
init(width: CGFloat, article: Article?) {
self.width = width
self.article = article
NotificationCenter.default.addObserver(self, selector: #selector(didImageDownloadingFailed), name: .kingfisherFail, object: nil)
}
private var imageSize: CGSize {
return imageDownloadingFailed ? .zero : CGSize(width: width, height: HomeCollectionViewCellComponentViewConstants.imageViewHeight + HomeCollectionViewCellComponentViewConstants.imageTopSpacing)
}
@objc func didImageDownloadingFailed(notification: Notification) {
print("didImageDownloadingFailed")
self.imageDownloadingFailed = true
}
HomeViewCollectionViewDelegate
final class HomeViewCollectionViewDelegate: NSObject, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
private var viewModel: HomeViewModel
init(viewModel: HomeViewModel) {
self.viewModel = viewModel
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
guard let article = viewModel.getArticle(at: indexPath) else { return CGSize(width: collectionView.frame.width, height: collectionView.frame.height) }
let sizeCalculator = HomeCollectionViewCellSizeCalculator(width: collectionView.frame.width, article: article)
return CGSize(width: collectionView.frame.width, height: sizeCalculator.itemSize.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 15
}
}
2
Answers
Try the following code
The problem is here:
At this point in time, you have a
sizeCalculator
, and it is listening to the notification because theinit(width:article:)
function added itself as an observer.Then you use the size calculator:
But now, with ^ this closing curly brace, you return from that method and don’t hold on to the size calculator, so it is dealloced, and is no longer alive to listen to any notifications.
You need to consider what object should be listening to the notification, and responding to the failure. Or indeed, maybe not consider using Notification Center at all.