zvonicek / ImageSlideshow

Swift image slideshow with circular scrolling, timer and full screen viewer
MIT License
1.77k stars 473 forks source link

Memory issue with SDWebImageSource #217

Open georgehl opened 6 years ago

georgehl commented 6 years ago

I posted an issue previously #214 although I think I've narrowed down the problem. We have a tableview with an imageslideshow inside the cell. When the tableview scrolls memory jumps from 30mb to 160mb and doesn't ever go back down.

This is our code for setting the imageslideshow: let imageSource = [SDWebImageSource(urlString: post.imageUrl1)!, ImageSource(image: UIImage(named: "Beach")!)] self.postSlideshow.setImageInputs(imageSource as! [InputSource])

Replacing the above code with: let imageSource = [ImageSource(image: UIImage(named: "Beach")!), ImageSource(image: UIImage(named: "Beach")!)] self.postSlideshow.setImageInputs(imageSource) fixes the memory problem.

Notes: we don't use currentPageChanged, willBeginDragging or didEndDecelerating closures. The image urls we use for SDWebImageSource have images under 500kb in size

Viktorfalkner commented 6 years ago

I also have this issue.

       var inputs = [SDWebImageSource]()
        if let imageURLStrings = associatedProperty.imageURLStrings {
            for imageString in imageURLStrings {
                let input = SDWebImageSource.init(urlString: imageString, placeholder: #imageLiteral(resourceName: "property-no-image"))
                inputs.append(input!)
            }
        }
        slideShow.setImageInputs(inputs)

can't seem to find a way to stop the leak

The pod works fantastic on individual screens, or callouts!

However once it's introduced into a tableview/tableview cell, it starts a massive memory leak which eventually causes the device to disconnect.

Is there a specific way to use this pod in a tableView? I just have cells with some text underneath, and a iamgeSlideShow above that.

spase84 commented 6 years ago

I have same issue with memory leaks when use imageSlideShow in tableView

CarioniStefano commented 5 years ago

Same problem here, 12 jpg image 3MB each. Memory usage over 500MB and application crashes

klassneckii commented 4 years ago

I faced this too and found a workaround, just limit RAM usage by SDWebImage by specifying cache size, for example to 15 MB or whatever you're found reasonable for you:

SDImageCache.shared().maxMemoryCost = 15 * 1024 * 1024

pratikgajbhiye222 commented 4 years ago

I end with the lots of images more than expectation , I think I stuck in for loop , can someone help me?

import UIKit
import AVFoundation
import ImageSlideshow

class MediaDetailsTableViewCell: UITableViewCell , ASAutoPlayVideoLayerContainer{

   var imageData = [SDWebImageSource]()

    @IBOutlet var slideshow: ImageSlideshow!

        @IBOutlet weak var fullNameOnFeed : UILabel!
        @IBOutlet weak var academyNameOnFeed : UILabel!
        @IBOutlet weak var pictureUrlOnFeed : UIImageView!
//        @IBOutlet weak var feedImageOnFeed : UIImageView!
        @IBOutlet weak var hashtagOnFeed : UILabel!
        @IBOutlet weak var sessionNameOnFeed : UILabel!
        @IBOutlet weak var sessionDetailsOnFeed : UILabel!

    var playerController: ASVideoPlayerController?
      var videoLayer: AVPlayerLayer = AVPlayerLayer()
      var videoURL: String? {
          didSet {
              if let videoURL = videoURL {
                  ASVideoPlayerController.sharedVideoPlayer.setupVideoFor(url: videoURL)
              }
              videoLayer.isHidden = videoURL == nil
            videoLayer.frame = self.frame
            videoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
            videoLayer.videoGravity = .resizeAspectFill
            videoLayer.frame = slideshow.bounds

          }
      }
        var item: MediaDetails? {
            didSet{
                guard let item = item  else {
                return
                }
                if let fullNameOnFeed = fullNameOnFeed {
                    fullNameOnFeed.text = item.fullName
                }
                if let academyNameOnFeed = academyNameOnFeed {
                    academyNameOnFeed.text = item.academyName
                }
                if let hashtagOnFeed = hashtagOnFeed {
                    hashtagOnFeed.text = item.hashtag
                }
                if let sessionNameOnFeed = sessionNameOnFeed {
                    sessionNameOnFeed.text = item.sessionName
                }
                if let sessionDetailsOnFeed = sessionDetailsOnFeed {
                    sessionDetailsOnFeed.text = item.sessionDetails
                }
                if let pictureUrl = item.pictureUrl {
                    pictureUrlOnFeed?.image = UIImage(named: pictureUrl)
                }
                if item.videoURL != nil {
                    if let videoLayerURL = item.videoURL {
                        self.videoURL = videoLayerURL
                        self.configureCell(imageUrl: nil, videoUrl: videoLayerURL)
                        print("video is \(videoLayerURL)")
                    }
                }

                else {
                let itemImages = item.feedImage
                if itemImages.count > 0 {
                    for url in itemImages {
                        let image = SDWebImageSource(urlString: url.images ?? "")
                            if let SDURL = image{
                                imageData.append(SDURL)
                        }
                        }
                        self.slideshow.setImageInputs(imageData)

                    }
                 self.configureCell(imageUrl: imageData, videoUrl: nil)

                }
            }
        }

        override func awakeFromNib() {
            super.awakeFromNib()
            videoLayer.backgroundColor = UIColor.clear.cgColor
            videoLayer.videoGravity = AVLayerVideoGravity.resize
            videoLayer.frame = slideshow.bounds
//            let tap = UITapGestureRecognizer(target: self, action: #selector(didTappedOnVideo))
//            videoLayer.addSublayer(tap)
            let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
            slideshow.isUserInteractionEnabled = true
            slideshow.addGestureRecognizer(tapGestureRecognizer)

            slideshow.layer.addSublayer(videoLayer)
            selectionStyle = .none

            //////
            slideshow.slideshowInterval = 5.0
            slideshow.pageIndicatorPosition = .init(horizontal: .center, vertical: .under)
            slideshow.contentScaleMode = UIViewContentMode.scaleAspectFill

            let pageControl = UIPageControl()
            pageControl.currentPageIndicatorTintColor = UIColor.lightGray
            pageControl.pageIndicatorTintColor = UIColor.black
            slideshow.pageIndicator = pageControl

            // optional way to show activity indicator during image load (skipping the line will show no activity indicator)
            slideshow.activityIndicator = DefaultActivityIndicator()
            slideshow.delegate = self as? ImageSlideshowDelegate

            // can be used with other sample sources as `afNetworkingSource`, `alamofireSource` or `sdWebImageSource` or `kingfisherSource

            let recognizer = UITapGestureRecognizer(target: self, action: #selector(MediaDetailsTableViewCell.didTap))
            slideshow.addGestureRecognizer(recognizer)

        }

    @objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
    {
        let _ = tapGestureRecognizer.view as! UIImageView
        print("tappedHo rha h")
        ASVideoPlayerController.sharedVideoPlayer.shouldPlay.toggle()
        // Your action
    }

    @objc func didTap(){

    }

    func configureCell(imageUrl: [SDWebImageSource]?,
                          videoUrl: String?) {
        guard let sdd = imageUrl else { return}
        self.slideshow.setImageInputs(sdd)
           self.videoURL = videoUrl
       }
        static var nib:UINib {
            return UINib(nibName: identifier, bundle: nil)
        }
       static var identifier: String {
            return String(describing: self)
        }
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
        }
    override func prepareForReuse() {
        super.prepareForReuse()
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        let horizontalMargin: CGFloat = 20
        let width: CGFloat = slideshow.bounds.width
        let height: CGFloat = slideshow.bounds.height
        videoLayer.frame = CGRect(x: 0, y: 0, width: width, height: height)

    }

    func visibleVideoHeight() -> CGFloat {
            let videoFrameInParentSuperView: CGRect? = self.superview?.superview?.convert(slideshow.frame, from: slideshow)
                  guard let videoFrame = videoFrameInParentSuperView,
                      let superViewFrame = superview?.frame else {
                       return 0
                  }
                  let visibleVideoFrame = videoFrame.intersection(superViewFrame)
                  return visibleVideoFrame.size.height
       }
}

I faced this too and found a workaround, just limit RAM usage by SDWebImage by specifying cache size, for example to 15 MB or whatever you're found reasonable for you:

SDImageCache.shared().maxMemoryCost = 15 * 1024 * 1024