daltoniam / Skeets

Fetch, cache, and display images via HTTP in Swift.
Apache License 2.0
191 stars 21 forks source link

Loading multiple images in a table view #15

Closed darer closed 9 years ago

darer commented 9 years ago

Hi! I want to say that Skeets helped me a lot and I want to thank you for that!

I'm facing one problem when I try to load a table view (2 images per cell/row, about 10 rows displayed on the screen). The first time I run the app all the images go crazy while loading. They show up, then they change (different images displayed one after another in the same position) and even after they are all loaded from the server, they remain shuffled. I'm new to programming and maybe I don't fully understand this, but I just can't find a solution. Do you have any idea why this is happening and how can I fix it?

Thanks!

darer commented 9 years ago

In my cellForRowAtIndexPath function I load the two images like this:

            ImageManager.sharedManager.fetch(completeUrlImageOne,
                progress: { (status: Double) in
                    //do someting while loading
                },success: { (data: NSData) in
                    cell.imageOneLoader.stopAnimating()
                    let imageToResize = UIImage(data: data)
                    let size = CGSizeMake(35, 35)
                    cell.imageOne.image = self.resizeImage(imageToResize!, newSize: size) //set the image data
                }, failure: { (error: NSError) in
                    //println("failed to get an image: \(error)")
            })

            ImageManager.sharedManager.fetch(completeUrlImageTwo,
                progress: { (status: Double) in
                    //println("updating some UI for this: \(status)") //useful if you have some kind of progress dialog as the image loads
                },success: { (data: NSData) in
                    //println("got an image!")
                    let imageToResize = UIImage(data: data)
                    let size = CGSizeMake(35, 35)
                    cell.imageTwo.image = self.resizeImage(imageToResize!, newSize: size) //set the image data
                }, failure: { (error: NSError) in
                    //println("failed to get an image: \(error)")
            })
daltoniam commented 9 years ago

Glad it helps out. I wrote an article on using a tableView with Skeets, check it out:

http://vluxe.io/build-swift-people.html

Point of interest (cellForRowAtIndexPath): https://github.com/Vluxe/SwiftPeople/blob/master/SwiftPeople/ViewController.swift

darer commented 9 years ago

Thanks, this worked! But now I'm getting another problem. A few of the images are not displaying at all. Since I display the same image on more than one row I can see that they are loaded, but they just don't show up in some rows. When I scroll up and down on the table to hide/show those rows the images appear. This happens to the exact same images at the exact same rows every time I run the app. Any suggestions?

darer commented 9 years ago

Now I noticed that it happens only when I show the same image twice. It shows in the first place and doesn't show in the second.

daltoniam commented 9 years ago

If you put a println() statement in the success closure does it print out twice?

darer commented 9 years ago

Nope, it doesn't.

daltoniam commented 9 years ago

Interesting, I would expect the println() in the success closure to be called twice if two image views are using it. Do you have any code that sets the image to nil?

darer commented 9 years ago

Here's the updated code in my cellForRowAtIndexPath:

                //Handle Logos
                cell.teamOneLogoImage.image = nil
                cell.teamTwoLogoImage.image = nil

                //if the cell is being recycled, make sure to cancel the old url it was loading.
                if completeUrlTeamOne != "" {
                    ImageManager.cancel(completeUrlTeamOne)
                }
                if completeUrlTeamTwo != "" {
                    ImageManager.cancel(completeUrlTeamTwo)
                }

                //fetch the images
                ImageManager.sharedManager.fetch(completeUrlTeamOne,
                    progress: { (status: Double) in
                        //do someting while loading
                    },success: { (data: NSData) in
                        cell.teamOneLogoLoader.stopAnimating()
                        let imageToResize = UIImage(data: data)
                        let size = CGSizeMake(35, 35)
                        cell.teamOneLogoImage.image = self.resizeImage(imageToResize!, newSize: size) //set the image data
                        println(completeUrlTeamOne)
                        completeUrlTeamOne = ""
                    }, failure: { (error: NSError) in
                        println("failed to get an image: \(error)")
                })

                ImageManager.sharedManager.fetch(completeUrlTeamTwo,
                    progress: { (status: Double) in
                        //println("updating some UI for this: \(status)") //useful if you have some kind of progress dialog as the image loads
                    },success: { (data: NSData) in
                        cell.teamTwoLogoLoader.stopAnimating()
                        let imageToResize = UIImage(data: data)
                        let size = CGSizeMake(35, 35)
                        cell.teamTwoLogoImage.image = self.resizeImage(imageToResize!, newSize: size) //set the image data
                        println(completeUrlTeamTwo)
                        completeUrlTeamTwo = ""
                    }, failure: { (error: NSError) in
                        println("failed to get an image: \(error)")
                })

                completeUrlTeamOne = urlBeginning + (teamOneDoc["logo"] as! String)
                completeUrlTeamTwo = urlBeginning + (teamTwoDoc["logo"] as! String)
daltoniam commented 9 years ago

Thanks for the code. I wasn't able to reproduce the behavior you are describing. I might look into the completeUrlTeamOne and completeUrlTeamTwo variables. You have those scoped as instance variables for the whole viewController and they might be overriding each other causing the cells to not finish. I also just pushed 0.9.5 tag for Skeets to support the SwiftHTTP updated.

longbowww commented 9 years ago

@daltoniam i just wondered what the

if let users = self.users {
if indexPath.row < users.count {

does in your article.

Is it just to be failsafe?

daltoniam commented 9 years ago

Correct. The if indexPath.row < users.count was just a failsafe, isn't necessary for it to work properly.

darer commented 9 years ago

I made it! You were right about the completeUrlTeamOne and completeUrlTeamTwo variables. I was working on some other things for the last few days, but when I got back to this today I found the problem. Life is good now :smile:

daltoniam commented 9 years ago

Nicely done. Glad you got it figured out and life is good :smile:.