How to disable TableView cell images download when they get into view









up vote
1
down vote

favorite












I have a TableView with ImageViews inside each cell. I want the images to get loaded once and remain like that but it seems that the images get loaded (downloaded, I'm getting them from an external API) as they get into visible area for user. It seems like a lazy load or something like that and I would like to disable it because if I scroll down then come back up most of the images get misplaced.



TableViewController.swift



cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)


BusinessLayer.swift



func getChampionThumbnailImage (championId: Int) -> UIImage 
return dataLayerRiot.getChampionThumbnailImage(championId: championId)



DataLayerRiot.swift



func getChampionThumbnailImage (championId: Int) -> UIImage 
var image: UIImage!

let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
let url = URL(string: urlString)
let session = URLSession.shared

let semaphore = DispatchSemaphore(value: 0)

session.dataTask(with: url!) (data, response, error) in
if error != nil
print("ERROR")
semaphore.signal()

else
image = UIImage(data: data!)!
semaphore.signal()

.resume()

semaphore.wait()
session.finishTasksAndInvalidate()

return image



Anyone know how to disable them loading as they get into visible area for the user and just have them "stored"?










share|improve this question



















  • 1




    Are you using dequeueReusableCell, if so its likely that could be causing the issue. You probably need to download the images and cache them, pulling the correct one back as necessary, maybe this will help stackoverflow.com/a/50443730/285190
    – Flexicoder
    Nov 9 at 13:03






  • 1




    Have a look at KingFisher [github.com/onevcat/Kingfisher]. It's main purpose is downloading and caching images.
    – Alan Sarraf
    Nov 9 at 13:10















up vote
1
down vote

favorite












I have a TableView with ImageViews inside each cell. I want the images to get loaded once and remain like that but it seems that the images get loaded (downloaded, I'm getting them from an external API) as they get into visible area for user. It seems like a lazy load or something like that and I would like to disable it because if I scroll down then come back up most of the images get misplaced.



TableViewController.swift



cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)


BusinessLayer.swift



func getChampionThumbnailImage (championId: Int) -> UIImage 
return dataLayerRiot.getChampionThumbnailImage(championId: championId)



DataLayerRiot.swift



func getChampionThumbnailImage (championId: Int) -> UIImage 
var image: UIImage!

let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
let url = URL(string: urlString)
let session = URLSession.shared

let semaphore = DispatchSemaphore(value: 0)

session.dataTask(with: url!) (data, response, error) in
if error != nil
print("ERROR")
semaphore.signal()

else
image = UIImage(data: data!)!
semaphore.signal()

.resume()

semaphore.wait()
session.finishTasksAndInvalidate()

return image



Anyone know how to disable them loading as they get into visible area for the user and just have them "stored"?










share|improve this question



















  • 1




    Are you using dequeueReusableCell, if so its likely that could be causing the issue. You probably need to download the images and cache them, pulling the correct one back as necessary, maybe this will help stackoverflow.com/a/50443730/285190
    – Flexicoder
    Nov 9 at 13:03






  • 1




    Have a look at KingFisher [github.com/onevcat/Kingfisher]. It's main purpose is downloading and caching images.
    – Alan Sarraf
    Nov 9 at 13:10













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I have a TableView with ImageViews inside each cell. I want the images to get loaded once and remain like that but it seems that the images get loaded (downloaded, I'm getting them from an external API) as they get into visible area for user. It seems like a lazy load or something like that and I would like to disable it because if I scroll down then come back up most of the images get misplaced.



TableViewController.swift



cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)


BusinessLayer.swift



func getChampionThumbnailImage (championId: Int) -> UIImage 
return dataLayerRiot.getChampionThumbnailImage(championId: championId)



DataLayerRiot.swift



func getChampionThumbnailImage (championId: Int) -> UIImage 
var image: UIImage!

let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
let url = URL(string: urlString)
let session = URLSession.shared

let semaphore = DispatchSemaphore(value: 0)

session.dataTask(with: url!) (data, response, error) in
if error != nil
print("ERROR")
semaphore.signal()

else
image = UIImage(data: data!)!
semaphore.signal()

.resume()

semaphore.wait()
session.finishTasksAndInvalidate()

return image



Anyone know how to disable them loading as they get into visible area for the user and just have them "stored"?










share|improve this question















I have a TableView with ImageViews inside each cell. I want the images to get loaded once and remain like that but it seems that the images get loaded (downloaded, I'm getting them from an external API) as they get into visible area for user. It seems like a lazy load or something like that and I would like to disable it because if I scroll down then come back up most of the images get misplaced.



TableViewController.swift



cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)


BusinessLayer.swift



func getChampionThumbnailImage (championId: Int) -> UIImage 
return dataLayerRiot.getChampionThumbnailImage(championId: championId)



DataLayerRiot.swift



func getChampionThumbnailImage (championId: Int) -> UIImage 
var image: UIImage!

let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
let url = URL(string: urlString)
let session = URLSession.shared

let semaphore = DispatchSemaphore(value: 0)

session.dataTask(with: url!) (data, response, error) in
if error != nil
print("ERROR")
semaphore.signal()

else
image = UIImage(data: data!)!
semaphore.signal()

.resume()

semaphore.wait()
session.finishTasksAndInvalidate()

return image



Anyone know how to disable them loading as they get into visible area for the user and just have them "stored"?







ios swift uitableview






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 9 at 14:57









rmaddy

234k27305371




234k27305371










asked Nov 9 at 12:53









Cristian G

317




317







  • 1




    Are you using dequeueReusableCell, if so its likely that could be causing the issue. You probably need to download the images and cache them, pulling the correct one back as necessary, maybe this will help stackoverflow.com/a/50443730/285190
    – Flexicoder
    Nov 9 at 13:03






  • 1




    Have a look at KingFisher [github.com/onevcat/Kingfisher]. It's main purpose is downloading and caching images.
    – Alan Sarraf
    Nov 9 at 13:10













  • 1




    Are you using dequeueReusableCell, if so its likely that could be causing the issue. You probably need to download the images and cache them, pulling the correct one back as necessary, maybe this will help stackoverflow.com/a/50443730/285190
    – Flexicoder
    Nov 9 at 13:03






  • 1




    Have a look at KingFisher [github.com/onevcat/Kingfisher]. It's main purpose is downloading and caching images.
    – Alan Sarraf
    Nov 9 at 13:10








1




1




Are you using dequeueReusableCell, if so its likely that could be causing the issue. You probably need to download the images and cache them, pulling the correct one back as necessary, maybe this will help stackoverflow.com/a/50443730/285190
– Flexicoder
Nov 9 at 13:03




Are you using dequeueReusableCell, if so its likely that could be causing the issue. You probably need to download the images and cache them, pulling the correct one back as necessary, maybe this will help stackoverflow.com/a/50443730/285190
– Flexicoder
Nov 9 at 13:03




1




1




Have a look at KingFisher [github.com/onevcat/Kingfisher]. It's main purpose is downloading and caching images.
– Alan Sarraf
Nov 9 at 13:10





Have a look at KingFisher [github.com/onevcat/Kingfisher]. It's main purpose is downloading and caching images.
– Alan Sarraf
Nov 9 at 13:10













3 Answers
3






active

oldest

votes

















up vote
0
down vote













You should save a task at memory like:



let task = = session.dataTask() 


And after you can cancel it anywhere by:



task.cancel()


Alternatively, if the object session is a URLSession instance, you can cancel it by:



session.invalidateAndCancel()





share|improve this answer



























    up vote
    0
    down vote













    Try SDWebImage for lazy loading the images in the UITableViewCell or UICollectionViewCell. Install it through cocoapods into your project.



    It is an asynchronous memory + disk image caching with automatic cache expiration handling.



    https://github.com/SDWebImage/SDWebImage



    Code:



    let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
    let url = URL(string: urlString)
    cell?.mainChampImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder.png"))





    share|improve this answer



























      up vote
      0
      down vote













      It sounds like you could benefit from doing some image caching. There are multiple ways to go about doing so, but from your example, it doesn't look like you need to go through the trouble of adding an entire library to do so. You can do it in a simple manner using NSCache.



      I created a class called ImageCache, and in this case it is a singleton, so that the cache is accessible throughout the entire application.



      import UIKit

      class ImageCache: NSObject
      static let sharedImageCache = ImageCache()

      // Initialize cache, specifying that your key type is AnyObject
      // and your value type is AnyObject. This is because NSCache requires
      // class types, not value types so we can't use <URL, UIImage>

      let imageCache = NSCache<AnyObject, AnyObject>()

      // Here we store the image, with the url as the key
      func add(image: UIImage, for url: URL)
      // we cast url as AnyObject because URL is not a class type, it's a value type
      imageCache.setObject(image, forKey: url as AnyObject)



      // This allows us to access the image from cache with the URL as the key
      // (e.g. cache[URL])
      func fetchImage(for url: URL) -> UIImage?
      var image: UIImage?

      // Casting url for the same reason as before, but we also want the result
      // as an image, so we cast that as well
      image = imageCache.object(forKey: url as AnyObject) as? UIImage
      return image




      So now we have some relatively simple caching in place. Now for how to use it:



      func getChampionThumbnailImage (championId: Int) -> UIImage 
      var image: UIImage!

      let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
      let url = URL(string: urlString)

      // Before, downloading the image, we check the cache to see if it exists and is stored.
      // If so, we can grab that image from the cache and avoid downloading it again.
      if let cachedImage = ImageCache.sharedImageCache.fetchImage(for: url)
      image = cachedImage
      return image


      let session = URLSession.shared

      let semaphore = DispatchSemaphore(value: 0)

      session.dataTask(with: url!) (data, response, error) in
      if error != nil
      print("ERROR")
      semaphore.signal()

      else
      image = UIImage(data: data!)!
      // Once the image is successfully downloaded the first time, add it to
      // the cache for later retrieval
      ImageCache.sharedImageCache.add(image: image, for: url!)
      semaphore.signal()

      .resume()

      semaphore.wait()
      session.finishTasksAndInvalidate()

      return image



      The reason the images are re-downloading is because a table view doesn't have unlimited cells. What happens is, as you scroll down, the cells that go off the screen are then recycled and re-used, so when you scroll back up, the images have to be grabbed again because they've been emptied out.



      You can avoid downloading the images again by implementing caching.



      Another way you can avoid having incorrect images is setting your image view to nil before you re-download the image. For example:



      cell?.mainChampImageView = nil
      cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)


      All of the above, along with making sure that you are dequeuing cells properly should address your issue.






      share|improve this answer




















        Your Answer






        StackExchange.ifUsing("editor", function ()
        StackExchange.using("externalEditor", function ()
        StackExchange.using("snippets", function ()
        StackExchange.snippets.init();
        );
        );
        , "code-snippets");

        StackExchange.ready(function()
        var channelOptions =
        tags: "".split(" "),
        id: "1"
        ;
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function()
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled)
        StackExchange.using("snippets", function()
        createEditor();
        );

        else
        createEditor();

        );

        function createEditor()
        StackExchange.prepareEditor(
        heartbeatType: 'answer',
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader:
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        ,
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        );



        );













         

        draft saved


        draft discarded


















        StackExchange.ready(
        function ()
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53226081%2fhow-to-disable-tableview-cell-images-download-when-they-get-into-view%23new-answer', 'question_page');

        );

        Post as a guest






























        3 Answers
        3






        active

        oldest

        votes








        3 Answers
        3






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        0
        down vote













        You should save a task at memory like:



        let task = = session.dataTask() 


        And after you can cancel it anywhere by:



        task.cancel()


        Alternatively, if the object session is a URLSession instance, you can cancel it by:



        session.invalidateAndCancel()





        share|improve this answer
























          up vote
          0
          down vote













          You should save a task at memory like:



          let task = = session.dataTask() 


          And after you can cancel it anywhere by:



          task.cancel()


          Alternatively, if the object session is a URLSession instance, you can cancel it by:



          session.invalidateAndCancel()





          share|improve this answer






















            up vote
            0
            down vote










            up vote
            0
            down vote









            You should save a task at memory like:



            let task = = session.dataTask() 


            And after you can cancel it anywhere by:



            task.cancel()


            Alternatively, if the object session is a URLSession instance, you can cancel it by:



            session.invalidateAndCancel()





            share|improve this answer












            You should save a task at memory like:



            let task = = session.dataTask() 


            And after you can cancel it anywhere by:



            task.cancel()


            Alternatively, if the object session is a URLSession instance, you can cancel it by:



            session.invalidateAndCancel()






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 9 at 13:00









            biloshkurskyi.ss

            7451026




            7451026






















                up vote
                0
                down vote













                Try SDWebImage for lazy loading the images in the UITableViewCell or UICollectionViewCell. Install it through cocoapods into your project.



                It is an asynchronous memory + disk image caching with automatic cache expiration handling.



                https://github.com/SDWebImage/SDWebImage



                Code:



                let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
                let url = URL(string: urlString)
                cell?.mainChampImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder.png"))





                share|improve this answer
























                  up vote
                  0
                  down vote













                  Try SDWebImage for lazy loading the images in the UITableViewCell or UICollectionViewCell. Install it through cocoapods into your project.



                  It is an asynchronous memory + disk image caching with automatic cache expiration handling.



                  https://github.com/SDWebImage/SDWebImage



                  Code:



                  let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
                  let url = URL(string: urlString)
                  cell?.mainChampImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder.png"))





                  share|improve this answer






















                    up vote
                    0
                    down vote










                    up vote
                    0
                    down vote









                    Try SDWebImage for lazy loading the images in the UITableViewCell or UICollectionViewCell. Install it through cocoapods into your project.



                    It is an asynchronous memory + disk image caching with automatic cache expiration handling.



                    https://github.com/SDWebImage/SDWebImage



                    Code:



                    let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
                    let url = URL(string: urlString)
                    cell?.mainChampImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder.png"))





                    share|improve this answer












                    Try SDWebImage for lazy loading the images in the UITableViewCell or UICollectionViewCell. Install it through cocoapods into your project.



                    It is an asynchronous memory + disk image caching with automatic cache expiration handling.



                    https://github.com/SDWebImage/SDWebImage



                    Code:



                    let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
                    let url = URL(string: urlString)
                    cell?.mainChampImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder.png"))






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 9 at 13:30









                    Sateesh

                    1,077413




                    1,077413




















                        up vote
                        0
                        down vote













                        It sounds like you could benefit from doing some image caching. There are multiple ways to go about doing so, but from your example, it doesn't look like you need to go through the trouble of adding an entire library to do so. You can do it in a simple manner using NSCache.



                        I created a class called ImageCache, and in this case it is a singleton, so that the cache is accessible throughout the entire application.



                        import UIKit

                        class ImageCache: NSObject
                        static let sharedImageCache = ImageCache()

                        // Initialize cache, specifying that your key type is AnyObject
                        // and your value type is AnyObject. This is because NSCache requires
                        // class types, not value types so we can't use <URL, UIImage>

                        let imageCache = NSCache<AnyObject, AnyObject>()

                        // Here we store the image, with the url as the key
                        func add(image: UIImage, for url: URL)
                        // we cast url as AnyObject because URL is not a class type, it's a value type
                        imageCache.setObject(image, forKey: url as AnyObject)



                        // This allows us to access the image from cache with the URL as the key
                        // (e.g. cache[URL])
                        func fetchImage(for url: URL) -> UIImage?
                        var image: UIImage?

                        // Casting url for the same reason as before, but we also want the result
                        // as an image, so we cast that as well
                        image = imageCache.object(forKey: url as AnyObject) as? UIImage
                        return image




                        So now we have some relatively simple caching in place. Now for how to use it:



                        func getChampionThumbnailImage (championId: Int) -> UIImage 
                        var image: UIImage!

                        let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
                        let url = URL(string: urlString)

                        // Before, downloading the image, we check the cache to see if it exists and is stored.
                        // If so, we can grab that image from the cache and avoid downloading it again.
                        if let cachedImage = ImageCache.sharedImageCache.fetchImage(for: url)
                        image = cachedImage
                        return image


                        let session = URLSession.shared

                        let semaphore = DispatchSemaphore(value: 0)

                        session.dataTask(with: url!) (data, response, error) in
                        if error != nil
                        print("ERROR")
                        semaphore.signal()

                        else
                        image = UIImage(data: data!)!
                        // Once the image is successfully downloaded the first time, add it to
                        // the cache for later retrieval
                        ImageCache.sharedImageCache.add(image: image, for: url!)
                        semaphore.signal()

                        .resume()

                        semaphore.wait()
                        session.finishTasksAndInvalidate()

                        return image



                        The reason the images are re-downloading is because a table view doesn't have unlimited cells. What happens is, as you scroll down, the cells that go off the screen are then recycled and re-used, so when you scroll back up, the images have to be grabbed again because they've been emptied out.



                        You can avoid downloading the images again by implementing caching.



                        Another way you can avoid having incorrect images is setting your image view to nil before you re-download the image. For example:



                        cell?.mainChampImageView = nil
                        cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)


                        All of the above, along with making sure that you are dequeuing cells properly should address your issue.






                        share|improve this answer
























                          up vote
                          0
                          down vote













                          It sounds like you could benefit from doing some image caching. There are multiple ways to go about doing so, but from your example, it doesn't look like you need to go through the trouble of adding an entire library to do so. You can do it in a simple manner using NSCache.



                          I created a class called ImageCache, and in this case it is a singleton, so that the cache is accessible throughout the entire application.



                          import UIKit

                          class ImageCache: NSObject
                          static let sharedImageCache = ImageCache()

                          // Initialize cache, specifying that your key type is AnyObject
                          // and your value type is AnyObject. This is because NSCache requires
                          // class types, not value types so we can't use <URL, UIImage>

                          let imageCache = NSCache<AnyObject, AnyObject>()

                          // Here we store the image, with the url as the key
                          func add(image: UIImage, for url: URL)
                          // we cast url as AnyObject because URL is not a class type, it's a value type
                          imageCache.setObject(image, forKey: url as AnyObject)



                          // This allows us to access the image from cache with the URL as the key
                          // (e.g. cache[URL])
                          func fetchImage(for url: URL) -> UIImage?
                          var image: UIImage?

                          // Casting url for the same reason as before, but we also want the result
                          // as an image, so we cast that as well
                          image = imageCache.object(forKey: url as AnyObject) as? UIImage
                          return image




                          So now we have some relatively simple caching in place. Now for how to use it:



                          func getChampionThumbnailImage (championId: Int) -> UIImage 
                          var image: UIImage!

                          let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
                          let url = URL(string: urlString)

                          // Before, downloading the image, we check the cache to see if it exists and is stored.
                          // If so, we can grab that image from the cache and avoid downloading it again.
                          if let cachedImage = ImageCache.sharedImageCache.fetchImage(for: url)
                          image = cachedImage
                          return image


                          let session = URLSession.shared

                          let semaphore = DispatchSemaphore(value: 0)

                          session.dataTask(with: url!) (data, response, error) in
                          if error != nil
                          print("ERROR")
                          semaphore.signal()

                          else
                          image = UIImage(data: data!)!
                          // Once the image is successfully downloaded the first time, add it to
                          // the cache for later retrieval
                          ImageCache.sharedImageCache.add(image: image, for: url!)
                          semaphore.signal()

                          .resume()

                          semaphore.wait()
                          session.finishTasksAndInvalidate()

                          return image



                          The reason the images are re-downloading is because a table view doesn't have unlimited cells. What happens is, as you scroll down, the cells that go off the screen are then recycled and re-used, so when you scroll back up, the images have to be grabbed again because they've been emptied out.



                          You can avoid downloading the images again by implementing caching.



                          Another way you can avoid having incorrect images is setting your image view to nil before you re-download the image. For example:



                          cell?.mainChampImageView = nil
                          cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)


                          All of the above, along with making sure that you are dequeuing cells properly should address your issue.






                          share|improve this answer






















                            up vote
                            0
                            down vote










                            up vote
                            0
                            down vote









                            It sounds like you could benefit from doing some image caching. There are multiple ways to go about doing so, but from your example, it doesn't look like you need to go through the trouble of adding an entire library to do so. You can do it in a simple manner using NSCache.



                            I created a class called ImageCache, and in this case it is a singleton, so that the cache is accessible throughout the entire application.



                            import UIKit

                            class ImageCache: NSObject
                            static let sharedImageCache = ImageCache()

                            // Initialize cache, specifying that your key type is AnyObject
                            // and your value type is AnyObject. This is because NSCache requires
                            // class types, not value types so we can't use <URL, UIImage>

                            let imageCache = NSCache<AnyObject, AnyObject>()

                            // Here we store the image, with the url as the key
                            func add(image: UIImage, for url: URL)
                            // we cast url as AnyObject because URL is not a class type, it's a value type
                            imageCache.setObject(image, forKey: url as AnyObject)



                            // This allows us to access the image from cache with the URL as the key
                            // (e.g. cache[URL])
                            func fetchImage(for url: URL) -> UIImage?
                            var image: UIImage?

                            // Casting url for the same reason as before, but we also want the result
                            // as an image, so we cast that as well
                            image = imageCache.object(forKey: url as AnyObject) as? UIImage
                            return image




                            So now we have some relatively simple caching in place. Now for how to use it:



                            func getChampionThumbnailImage (championId: Int) -> UIImage 
                            var image: UIImage!

                            let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
                            let url = URL(string: urlString)

                            // Before, downloading the image, we check the cache to see if it exists and is stored.
                            // If so, we can grab that image from the cache and avoid downloading it again.
                            if let cachedImage = ImageCache.sharedImageCache.fetchImage(for: url)
                            image = cachedImage
                            return image


                            let session = URLSession.shared

                            let semaphore = DispatchSemaphore(value: 0)

                            session.dataTask(with: url!) (data, response, error) in
                            if error != nil
                            print("ERROR")
                            semaphore.signal()

                            else
                            image = UIImage(data: data!)!
                            // Once the image is successfully downloaded the first time, add it to
                            // the cache for later retrieval
                            ImageCache.sharedImageCache.add(image: image, for: url!)
                            semaphore.signal()

                            .resume()

                            semaphore.wait()
                            session.finishTasksAndInvalidate()

                            return image



                            The reason the images are re-downloading is because a table view doesn't have unlimited cells. What happens is, as you scroll down, the cells that go off the screen are then recycled and re-used, so when you scroll back up, the images have to be grabbed again because they've been emptied out.



                            You can avoid downloading the images again by implementing caching.



                            Another way you can avoid having incorrect images is setting your image view to nil before you re-download the image. For example:



                            cell?.mainChampImageView = nil
                            cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)


                            All of the above, along with making sure that you are dequeuing cells properly should address your issue.






                            share|improve this answer












                            It sounds like you could benefit from doing some image caching. There are multiple ways to go about doing so, but from your example, it doesn't look like you need to go through the trouble of adding an entire library to do so. You can do it in a simple manner using NSCache.



                            I created a class called ImageCache, and in this case it is a singleton, so that the cache is accessible throughout the entire application.



                            import UIKit

                            class ImageCache: NSObject
                            static let sharedImageCache = ImageCache()

                            // Initialize cache, specifying that your key type is AnyObject
                            // and your value type is AnyObject. This is because NSCache requires
                            // class types, not value types so we can't use <URL, UIImage>

                            let imageCache = NSCache<AnyObject, AnyObject>()

                            // Here we store the image, with the url as the key
                            func add(image: UIImage, for url: URL)
                            // we cast url as AnyObject because URL is not a class type, it's a value type
                            imageCache.setObject(image, forKey: url as AnyObject)



                            // This allows us to access the image from cache with the URL as the key
                            // (e.g. cache[URL])
                            func fetchImage(for url: URL) -> UIImage?
                            var image: UIImage?

                            // Casting url for the same reason as before, but we also want the result
                            // as an image, so we cast that as well
                            image = imageCache.object(forKey: url as AnyObject) as? UIImage
                            return image




                            So now we have some relatively simple caching in place. Now for how to use it:



                            func getChampionThumbnailImage (championId: Int) -> UIImage 
                            var image: UIImage!

                            let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
                            let url = URL(string: urlString)

                            // Before, downloading the image, we check the cache to see if it exists and is stored.
                            // If so, we can grab that image from the cache and avoid downloading it again.
                            if let cachedImage = ImageCache.sharedImageCache.fetchImage(for: url)
                            image = cachedImage
                            return image


                            let session = URLSession.shared

                            let semaphore = DispatchSemaphore(value: 0)

                            session.dataTask(with: url!) (data, response, error) in
                            if error != nil
                            print("ERROR")
                            semaphore.signal()

                            else
                            image = UIImage(data: data!)!
                            // Once the image is successfully downloaded the first time, add it to
                            // the cache for later retrieval
                            ImageCache.sharedImageCache.add(image: image, for: url!)
                            semaphore.signal()

                            .resume()

                            semaphore.wait()
                            session.finishTasksAndInvalidate()

                            return image



                            The reason the images are re-downloading is because a table view doesn't have unlimited cells. What happens is, as you scroll down, the cells that go off the screen are then recycled and re-used, so when you scroll back up, the images have to be grabbed again because they've been emptied out.



                            You can avoid downloading the images again by implementing caching.



                            Another way you can avoid having incorrect images is setting your image view to nil before you re-download the image. For example:



                            cell?.mainChampImageView = nil
                            cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)


                            All of the above, along with making sure that you are dequeuing cells properly should address your issue.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Nov 9 at 21:23









                            droberson

                            111




                            111



























                                 

                                draft saved


                                draft discarded















































                                 


                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53226081%2fhow-to-disable-tableview-cell-images-download-when-they-get-into-view%23new-answer', 'question_page');

                                );

                                Post as a guest














































































                                Popular posts from this blog

                                Use pre created SQLite database for Android project in kotlin

                                Darth Vader #20

                                Ondo