I looked at several answers for this problem but none helped.
vc1 is a regular vc, I grab 20 images from firebase, in vc2 I use ARKit to display those images upon user selection. I have a collectionView in vc2 that paginates 20 more images from firebase. The problem is when the next 20 images are loading and I start scrolling, the app crashes with Message from debugger: Terminated due to memory issue
. When scrolling those new images, I look at the memory graph and it shoots up to 1 gig, so that's the reason for the crash. ARKit and the nodes I have floating around also contribute to the memory bump but they are not the reason for the crash as stated below.
1- Inside the cell I use SDWebImage
to display the image inside the imageView. Once I comment out SDWebImage
everything works, scrolling is smooth, and no more crashes but of course I can't see the image. I switched to URLSession.shared.dataTask
and the same memory issue reoccurs.
2- The images were initially taken with the iPhone full screen camera and saved with jpegData(compressionQuality: 0.3).
The cell size is 40x40. Inside the the SDWebImage
completion block I tried to resize the image but the memory crash still persists.
3- I used Instruments
> Leaks
to look for memory leaks and a few Foundation leaks appeared but when I dismiss vc2 Deinit
always runs. Inside vc2 there aren't any long running timers or loops and I use [weak self]
inside all of the closures.
4- As I stated in the second point the problem is definitely the imageView/image because once I remove it from the process everything works fine. If I don't show any images everything works fine (40 red imageViews with no images inside of them will appear).
What can I do to fix this issue?
Paginating to pull more images
for child in snapshot.children.allObjects as! [DataSnapshot] {
guard let dict = child.value as? [String:Any] else { continue }
let post = Post(dict: dict)
datasource.append(post)
let lastIndex = datasource.count - 1
let indexPath = IndexPath(item: lastIndex, section: 0)
UIView.performWithoutAnimation {
collectionView.insertItems(at: [indexPath])
}
}
cellForItem:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath) as! PostCell
cell.resetAll()
cell.post = dataSource[indexPath.item]
return cell
}
PostCell
private lazy var imageView: UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.contentMode = .scaleAspectFill
iv.layer.cornerRadius = 15
iv.layer.masksToBounds = true
iv.backgroundColor = .red
iv.isHidden = true
return iv
}()
private lazy var spinner: UIActivityIndicatorView = {
let actIndi = UIActivityIndicatorView(style: UIActivityIndicatorView.Style.medium) // ...
}()
var post: Post? {
didSet {
guard let urlSr = post?.urlStr, let url = URL(string: urlSr) else { return }
spinner.startAnimating()
// if I comment this out everything works fine
imageView.sd_setImage(with: url, placeholderImage: placeHolderImage, options: [], completed: {
[weak self] (image, error, cache, url) in
// in here I tried resizing the image but no diff
DispatchQueue.main.async { [weak self] in
self?.showAll()
}
})
setAnchors()
}
}
func resetAll() {
spinner.stopAnimating()
imageView.image = nil
imageView.removeFromSuperView()
imageView.isHidden = true
}
func showAll() {
spinner.stopAnimating()
imageView.isHidden = false
}
func setAnchors() {
contentView.addSubview(imageView)
imageView.addSubview(cellSpinner)
// imageView is pinned to all sides
}