Why my image is not display immediately after downloaded?

1.3k views Asked by At

I am having problem with async programming.I have a UIScrollView which will display multiple images(3~10) when I enter into detail view.So,there are two process that I currently working on.First,When I enter to the detail view,the post request which will call api to display detail data(images and data).Second,when I get the detail data,I have to download the images again which are from array(images with url).

I dont know whats wrong with my code.And also I am new to async programming.

My problem is when I first enter to UIScrollView,which was stucking at indicator

http://puu.sh/ijggV/fa90d7baed.png

When I go to the UITableViewCell and enter to UIScrollView again after three photo was downloaded,

http://puu.sh/ijgkN/d356f521b7.png

Is that because of ViewWillAppear? When I tried ViewDidLoad,the images doesn't show and stuck at loading even I change the tab multiple times

Here is my View Controller

import UIKit
import Kingfisher

class SecondViewController: UIViewController,AuctionAPIProtocol{

@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var imageIndicator: UIActivityIndicatorView!

var api : AuctionAPI?
var preferredViews: [UIView]!
var detailData : [AuctionModel] = []
var images = [UIImage]()

override func viewWillAppear(animated: Bool) {

    api = AuctionAPI(delegate: self)

    super.viewWillAppear(true)

    //let images = [UIImage(named: "Image1")!, UIImage(named: "Image2")!, UIImage(named: "Image3")!]
    self.preferredViews = [UIView]()

    if self.detailData.isEmpty{
        self.imageIndicator?.center
        self.imageIndicator?.startAnimating()

        // Start call the api to get the detail data
        self.getAuctionDetailPhotos()
        println("Auction Call")
    }

    // When the api get the detail data and downloaded the images,the image will show in the scroll view
    if images != []{
        println("Condition 1 In")
        let photos : [UIImage] = self.images
        for image in photos {
            let preferredView = UIView(frame: CGRectMake(0, 0, image.size.width, image.size.height))
            let imageView = UIImageView(frame: CGRectMake(0, 0, image.size.width, image.size.height))
            imageView.image = image
            imageView.contentMode = .ScaleAspectFit
            imageView.clipsToBounds = true
            preferredView.setTranslatesAutoresizingMaskIntoConstraints(false)
            imageView.setTranslatesAutoresizingMaskIntoConstraints(false)
            preferredView.addSubview(imageView)
            scrollView.addSubview(preferredView)

            preferredViews.append(preferredView)
        }
        self.imageIndicator?.stopAnimating()
    }
}

func getAuctionDetailPhotos(){
    api?.getAuctionDetail()
}

// This is one of the method from AuctionAPIProtocol which will went into results using delegate after API Request done
func didGetTheDetail(results: NSDictionary) {
    var detail : NSDictionary = results["body"] as! NSDictionary
    dispatch_async(dispatch_get_main_queue(),{
        self.detailData = AuctionModel.dictWithJSON(detail)
        println("Auction Call Ended")
        if !(self.detailData.isEmpty){

            var urlString = self.detailData[0].images as [String]

            for url in urlString {

                let imageUrl = NSURL(string: url)
                // This is image downloading library that i using now named Kingfisher                    

                         KingfisherManager.sharedManager.retrieveImageWithURL(imageUrl!, optionsInfo: nil,
                            progressBlock: nil, completionHandler: { (image, error, cacheType, imageURL) -> () in

                        if var dimage = image {
                            self.images.append(dimage)
                            println("Photo Download Completed")
                            //println(self.images)
                        } else {
                            println("Error Downloading images")
                        }
                })
            }
        }
    })
}


override func updateViewConstraints() {
    super.updateViewConstraints()

    if !(images.isEmpty){
        println("Condtion 2 In")
        var prevView: UIView? = nil
        for preferredView in preferredViews {
            let imageView = preferredView.subviews[0] as! UIImageView
            preferredView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[imageView]|",
                options: nil, metrics: nil, views: ["imageView": imageView]))
            preferredView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[imageView]|",
                options: nil, metrics: nil, views: ["imageView": imageView]))

            if prevView == nil {
                scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[preferredView(==scrollView)]",
                    options: nil, metrics: nil, views: ["scrollView": scrollView, "preferredView": preferredView]))
            } else {
                scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[prevView][preferredView(==scrollView)]",
                    options: nil, metrics: nil, views: ["scrollView": scrollView, "prevView": prevView!, "preferredView": preferredView]))
            }
            scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[preferredView(==scrollView)]",
                options: nil, metrics: nil, views: ["scrollView": scrollView, "preferredView": preferredView]))

            prevView = preferredView
        }
    }
}


override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if !(images.isEmpty){
        println("Condition 3 In")
        let contentWidth = CGFloat(preferredViews.count) * scrollView.bounds.width
        let contentHeight = scrollView.bounds.height
        scrollView.contentSize = CGSizeMake(contentWidth, contentHeight)
    }
}

}

Any help please?I really need help.

1

There are 1 answers

2
onevcat On BEST ANSWER

You may need to put the "if images != []{}" block currently in the viewWillAppear into the Kingfisher's downloading completion handler. And since you are downloading multiple images, a dispatch group will help you to wait all downloads get over.

I am not sure if it works for you, but I made a little change based on your code. You can find it here.